diff --git a/app/chain/__init__.py b/app/chain/__init__.py index d5591509..8de3b680 100644 --- a/app/chain/__init__.py +++ b/app/chain/__init__.py @@ -385,14 +385,15 @@ class ChainBase(metaclass=ABCMeta): """ return self.run_module("post_torrents_message", message=message, torrents=torrents) - def scrape_metadata(self, path: Path, mediainfo: MediaInfo) -> None: + def scrape_metadata(self, path: Path, mediainfo: MediaInfo, scrap: bool = settings.SCRAP_METADATA) -> None: """ 刮削元数据 :param path: 媒体文件路径 :param mediainfo: 识别的媒体信息 + :param scrap: 是否刮削 :return: 成功或失败 """ - if settings.SCRAP_METADATA: + if scrap: return self.run_module("scrape_metadata", path=path, mediainfo=mediainfo) return None diff --git a/app/chain/transfer.py b/app/chain/transfer.py index 2e210072..e2126b39 100644 --- a/app/chain/transfer.py +++ b/app/chain/transfer.py @@ -253,10 +253,10 @@ class TransferChain(ChainBase): # 如果未开启新增已入库媒体是否跟随TMDB信息变化则根据tmdbid查询之前的title if not settings.SCRAP_FOLLOW_TMDB: - transfer_historys = self.transferhis.get_by(tmdbid=file_mediainfo.tmdb_id, - mtype=file_mediainfo.type.value) - if transfer_historys: - file_mediainfo.title = transfer_historys[0].title + transfer_history = self.transferhis.get_by_type_tmdbid(tmdbid=file_mediainfo.tmdb_id, + mtype=file_mediainfo.type.value) + if transfer_history: + file_mediainfo.title = transfer_history.title logger.info(f"{file_path.name} 识别为:{file_mediainfo.type.value} {file_mediainfo.title_year}") diff --git a/app/core/meta/words.py b/app/core/meta/words.py index e0f466a7..213938ec 100644 --- a/app/core/meta/words.py +++ b/app/core/meta/words.py @@ -28,7 +28,23 @@ class WordsMatcher(metaclass=Singleton): if not word: continue try: - if word.count(" => "): + if word.count(" => ") and word.count(" && ") and word.count(" >> ") and word.count(" <> "): + # 替换词 + thc = re.findall(r'(.*?)\s*=>', word)[0] + # 被替换词 + bthc = re.findall(r'=>\s*(.*?)\s*&&', word)[0] + # 集偏移前字段 + pyq = re.findall(r'&&\s*(.*?)\s*<>', word)[0] + # 集偏移后字段 + pyh = re.findall(r'<>(.*?)\s*>>', word)[0] + # 集偏移 + offsets = re.findall(r'>>\s*(.*?)$', word)[0] + # 替换词 + title, message, state = self.__replace_regex(title, thc, bthc) + if state: + # 替换词成功再进行集偏移 + title, message, state = self.__episode_offset(title, pyq, pyh, offsets) + elif word.count(" => "): # 替换词 strings = word.split(" => ") title, message, state = self.__replace_regex(title, strings[0], strings[1]) diff --git a/app/db/models/transferhistory.py b/app/db/models/transferhistory.py index a3a8b323..88e172bb 100644 --- a/app/db/models/transferhistory.py +++ b/app/db/models/transferhistory.py @@ -86,7 +86,7 @@ class TransferHistory(Base): @staticmethod def list_by(db: Session, mtype: str = None, title: str = None, year: str = None, season: str = None, - episode: str = None, tmdbid: int = None): + episode: str = None, tmdbid: int = None, dest: str = None): """ 据tmdbid、season、season_episode查询转移记录 tmdbid + mtype 或 title + year 必输 @@ -98,16 +98,19 @@ class TransferHistory(Base): return db.query(TransferHistory).filter(TransferHistory.tmdbid == tmdbid, TransferHistory.type == mtype, TransferHistory.seasons == season, - TransferHistory.episodes == episode).all() + TransferHistory.episodes == episode, + TransferHistory.dest == dest).all() elif season: # 查询一季 return db.query(TransferHistory).filter(TransferHistory.tmdbid == tmdbid, TransferHistory.type == mtype, - TransferHistory.seasons == season).all() + TransferHistory.seasons == season, + TransferHistory.dest == dest).all() else: # 查询所有 return db.query(TransferHistory).filter(TransferHistory.tmdbid == tmdbid, - TransferHistory.type == mtype).all() + TransferHistory.type == mtype, + TransferHistory.dest == dest).all() # 标题 + 年份 elif title and year: # 电视剧某季某集 @@ -115,19 +118,30 @@ class TransferHistory(Base): return db.query(TransferHistory).filter(TransferHistory.title == title, TransferHistory.year == year, TransferHistory.seasons == season, - TransferHistory.episodes == episode).all() + TransferHistory.episodes == episode, + TransferHistory.dest == dest).all() # 电视剧某季 elif season: return db.query(TransferHistory).filter(TransferHistory.title == title, TransferHistory.year == year, - TransferHistory.seasons == season).all() + TransferHistory.seasons == season, + TransferHistory.dest == dest).all() # 电视剧所有季集|电影 else: return db.query(TransferHistory).filter(TransferHistory.title == title, - TransferHistory.year == year).all() + TransferHistory.year == year, + TransferHistory.dest == dest).all() return [] + @staticmethod + def get_by_type_tmdbid(db: Session, mtype: str = None, tmdbid: int = None): + """ + 据tmdbid、type查询转移记录 + """ + return db.query(TransferHistory).filter(TransferHistory.tmdbid == tmdbid, + TransferHistory.type == mtype).first() + @staticmethod def update_download_hash(db: Session, historyid: int = None, download_hash: str = None): db.query(TransferHistory).filter(TransferHistory.id == historyid).update( diff --git a/app/db/transferhistory_oper.py b/app/db/transferhistory_oper.py index da7c86a7..98902841 100644 --- a/app/db/transferhistory_oper.py +++ b/app/db/transferhistory_oper.py @@ -52,18 +52,27 @@ class TransferHistoryOper(DbOper): return TransferHistory.statistic(self._db, days) def get_by(self, title: str = None, year: str = None, mtype: str = None, - season: str = None, episode: str = None, tmdbid: int = None) -> List[TransferHistory]: + season: str = None, episode: str = None, tmdbid: int = None, dest: str = None) -> List[TransferHistory]: """ 按类型、标题、年份、季集查询转移记录 """ return TransferHistory.list_by(db=self._db, mtype=mtype, title=title, + dest=dest, year=year, season=season, episode=episode, tmdbid=tmdbid) + def get_by_type_tmdbid(self, mtype: str = None, tmdbid: int = None) -> TransferHistory: + """ + 按类型、tmdb查询转移记录 + """ + return TransferHistory.get_by_type_tmdbid(db=self._db, + mtype=mtype, + tmdbid=tmdbid) + def delete(self, historyid): """ 删除转移记录 diff --git a/app/plugins/dirmonitor/__init__.py b/app/plugins/dirmonitor/__init__.py index 65c04190..bc4cacd2 100644 --- a/app/plugins/dirmonitor/__init__.py +++ b/app/plugins/dirmonitor/__init__.py @@ -270,10 +270,10 @@ class DirMonitor(_PluginBase): # 如果未开启新增已入库媒体是否跟随TMDB信息变化则根据tmdbid查询之前的title if not settings.SCRAP_FOLLOW_TMDB: - transfer_historys = self.transferhis.get_by(tmdbid=mediainfo.tmdb_id, - mtype=mediainfo.type.value) - if transfer_historys: - mediainfo.title = transfer_historys[0].title + transfer_history = self.transferhis.get_by_type_tmdbid(tmdbid=mediainfo.tmdb_id, + mtype=mediainfo.type.value) + if transfer_history: + mediainfo.title = transfer_history.title logger.info(f"{file_path.name} 识别为:{mediainfo.type.value} {mediainfo.title_year}") # 更新媒体图片 diff --git a/app/plugins/libraryscraper/__init__.py b/app/plugins/libraryscraper/__init__.py index 8b61fef7..ea81ca1a 100644 --- a/app/plugins/libraryscraper/__init__.py +++ b/app/plugins/libraryscraper/__init__.py @@ -321,6 +321,8 @@ class LibraryScraper(_PluginBase): meta_info = MetaInfo(file.name) # 合并 meta_info.merge(dir_meta) + # 是否刮削 + scrap_metadata = settings.SCRAP_METADATA # 识别媒体信息 if not mediainfo: @@ -352,13 +354,14 @@ class LibraryScraper(_PluginBase): # 如果未开启新增已入库媒体是否跟随TMDB信息变化则根据tmdbid查询之前的title if not settings.SCRAP_FOLLOW_TMDB: - transfer_historys = self.transferhis.get_by(tmdbid=mediainfo.tmdb_id, - mtype=mediainfo.type.value) - if transfer_historys: - mediainfo.title = transfer_historys[0].title + transfer_history = self.transferhis.get_by_type_tmdbid(tmdbid=mediainfo.tmdb_id, + mtype=mediainfo.type.value) + if transfer_history: + mediainfo.title = transfer_history.title # 覆盖模式时,提前删除nfo if self._mode in ["force_all", "force_nfo"]: + scrap_metadata = True nfo_files = SystemUtils.list_files(path, [".nfo"]) for nfo_file in nfo_files: try: @@ -369,6 +372,7 @@ class LibraryScraper(_PluginBase): # 覆盖模式时,提前删除图片文件 if self._mode in ["force_all", "force_image"]: + scrap_metadata = True image_files = SystemUtils.list_files(path, [".jpg", ".png"]) for image_file in image_files: if ".actors" in str(image_file): @@ -380,7 +384,7 @@ class LibraryScraper(_PluginBase): print(str(err)) # 刮削单个文件 - self.chain.scrape_metadata(path=file, mediainfo=mediainfo) + self.chain.scrape_metadata(path=file, mediainfo=mediainfo, scrap=scrap_metadata) @staticmethod def __get_tmdbid_from_nfo(file_path: Path): diff --git a/app/plugins/mediasyncdel/__init__.py b/app/plugins/mediasyncdel/__init__.py index 163f9147..5e410c33 100644 --- a/app/plugins/mediasyncdel/__init__.py +++ b/app/plugins/mediasyncdel/__init__.py @@ -57,6 +57,7 @@ class MediaSyncDel(_PluginBase): _notify = False _del_source = False _exclude_path = None + _library_path = None _transferhis = None _downloadhis = None qb = None @@ -80,6 +81,7 @@ class MediaSyncDel(_PluginBase): self._notify = config.get("notify") self._del_source = config.get("del_source") self._exclude_path = config.get("exclude_path") + self._library_path = config.get("library_path") if self._enabled and str(self._sync_type) == "log": self._scheduler = BackgroundScheduler(timezone=settings.TZ) @@ -231,6 +233,28 @@ class MediaSyncDel(_PluginBase): } ] }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + }, + 'content': [ + { + 'component': 'VTextarea', + 'props': { + 'model': 'library_path', + 'rows': '2', + 'label': '媒体库路径', + 'placeholder': '媒体服务器路径:MoviePilot路径(一行一个)' + } + } + ] + } + ] + }, { 'component': 'VRow', 'content': [ @@ -260,6 +284,7 @@ class MediaSyncDel(_PluginBase): "enabled": False, "notify": True, "del_source": False, + "library_path": "", "sync_type": "webhook", "cron": "*/30 * * * *", "exclude_path": "", @@ -528,6 +553,7 @@ class MediaSyncDel(_PluginBase): # 查询转移记录 msg, transfer_history = self.__get_transfer_his(media_type=media_type, media_name=media_name, + media_path=media_path, tmdb_id=tmdb_id, season_num=season_num, episode_num=episode_num) @@ -545,11 +571,6 @@ class MediaSyncDel(_PluginBase): stop_cnt = 0 error_cnt = 0 for transferhis in transfer_history: - title = transferhis.title - if title not in media_name: - logger.warn( - f"当前转移记录 {transferhis.id} {title} {transferhis.tmdbid} 与删除媒体{media_name}不符,防误删,暂不自动删除") - continue image = transferhis.image year = transferhis.year @@ -626,12 +647,11 @@ class MediaSyncDel(_PluginBase): # 保存历史 self.save_data("history", history) - def __get_transfer_his(self, media_type: str, media_name: str, + def __get_transfer_his(self, media_type: str, media_name: str, media_path: str, tmdb_id: int, season_num: int, episode_num: int): """ 查询转移记录 """ - # 季数 if season_num: season_num = str(season_num).rjust(2, '0') @@ -642,16 +662,25 @@ class MediaSyncDel(_PluginBase): # 类型 mtype = MediaType.MOVIE if media_type in ["Movie", "MOV"] else MediaType.TV + # 处理路径映射 (处理同一媒体多分辨率的情况) + if self._library_path: + paths = self._library_path.split("\n") + for path in paths: + sub_paths = path.split(":") + media_path = media_path.replace(sub_paths[0], sub_paths[1]).replace('\\', '/') + # 删除电影 if mtype == MediaType.MOVIE: msg = f'电影 {media_name} {tmdb_id}' transfer_history: List[TransferHistory] = self._transferhis.get_by(tmdbid=tmdb_id, - mtype=mtype.value) + mtype=mtype.value, + dest=media_path) # 删除电视剧 elif mtype == MediaType.TV and not season_num and not episode_num: msg = f'剧集 {media_name} {tmdb_id}' transfer_history: List[TransferHistory] = self._transferhis.get_by(tmdbid=tmdb_id, - mtype=mtype.value) + mtype=mtype.value, + dest=media_path) # 删除季 S02 elif mtype == MediaType.TV and season_num and not episode_num: if not season_num or not str(season_num).isdigit(): @@ -660,7 +689,8 @@ class MediaSyncDel(_PluginBase): msg = f'剧集 {media_name} S{season_num} {tmdb_id}' transfer_history: List[TransferHistory] = self._transferhis.get_by(tmdbid=tmdb_id, mtype=mtype.value, - season=f'S{season_num}') + season=f'S{season_num}', + dest=media_path) # 删除剧集S02E02 elif mtype == MediaType.TV and season_num and episode_num: if not season_num or not str(season_num).isdigit() or not episode_num or not str(episode_num).isdigit(): @@ -670,7 +700,8 @@ class MediaSyncDel(_PluginBase): transfer_history: List[TransferHistory] = self._transferhis.get_by(tmdbid=tmdb_id, mtype=mtype.value, season=f'S{season_num}', - episode=f'E{episode_num}') + episode=f'E{episode_num}', + dest=media_path) else: return "", [] @@ -723,26 +754,36 @@ class MediaSyncDel(_PluginBase): logger.info(f"媒体路径 {media_path} 已被排除,暂不处理") return + # 处理路径映射 (处理同一媒体多分辨率的情况) + if self._library_path: + paths = self._library_path.split("\n") + for path in paths: + sub_paths = path.split(":") + media_path = media_path.replace(sub_paths[0], sub_paths[1]).replace('\\', '/') + # 获取删除的记录 # 删除电影 if media_type == "Movie": msg = f'电影 {media_name}' transfer_history: List[TransferHistory] = self._transferhis.get_by( title=media_name, - year=media_year) + year=media_year, + dest=media_path) # 删除电视剧 elif media_type == "Series": msg = f'剧集 {media_name}' transfer_history: List[TransferHistory] = self._transferhis.get_by( title=media_name, - year=media_year) + year=media_year, + dest=media_path) # 删除季 S02 elif media_type == "Season": msg = f'剧集 {media_name} {media_season}' transfer_history: List[TransferHistory] = self._transferhis.get_by( title=media_name, year=media_year, - season=media_season) + season=media_season, + dest=media_path) # 删除剧集S02E02 elif media_type == "Episode": msg = f'剧集 {media_name} {media_season}{media_episode}' @@ -750,7 +791,8 @@ class MediaSyncDel(_PluginBase): title=media_name, year=media_year, season=media_season, - episode=media_episode) + episode=media_episode, + dest=media_path) else: continue @@ -768,11 +810,6 @@ class MediaSyncDel(_PluginBase): stop_cnt = 0 error_cnt = 0 for transferhis in transfer_history: - title = transferhis.title - if title not in media_name: - logger.warn( - f"当前转移记录 {transferhis.id} {title} {transferhis.tmdbid} 与删除媒体{media_name}不符,防误删,暂不自动删除") - continue image = transferhis.image # 0、删除转移记录 self._transferhis.delete(transferhis.id)