From cd7f688e78204863c41bb4e3b4666fa582e6faf3 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 17 Dec 2023 10:49:00 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E5=88=AE=E5=89=8A=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E6=94=AF=E6=8C=81=E8=A6=86=E7=9B=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/chain/__init__.py | 8 +++-- app/modules/douban/__init__.py | 13 +++++++-- app/modules/douban/scraper.py | 46 +++++++++++++++++------------ app/modules/themoviedb/__init__.py | 17 ++++++++--- app/modules/themoviedb/scraper.py | 47 ++++++++++++++++++------------ 5 files changed, 86 insertions(+), 45 deletions(-) diff --git a/app/chain/__init__.py b/app/chain/__init__.py index bfbe846a..94dfd43e 100644 --- a/app/chain/__init__.py +++ b/app/chain/__init__.py @@ -421,15 +421,19 @@ class ChainBase(metaclass=ABCMeta): """ return self.run_module("post_torrents_message", message=message, torrents=torrents) - def scrape_metadata(self, path: Path, mediainfo: MediaInfo, transfer_type: str) -> None: + def scrape_metadata(self, path: Path, mediainfo: MediaInfo, transfer_type: str, + force_nfo: bool = False, force_img: bool = False) -> None: """ 刮削元数据 :param path: 媒体文件路径 :param mediainfo: 识别的媒体信息 :param transfer_type: 转移模式 + :param force_nfo: 强制刮削nfo + :param force_img: 强制刮削图片 :return: 成功或失败 """ - self.run_module("scrape_metadata", path=path, mediainfo=mediainfo, transfer_type=transfer_type) + self.run_module("scrape_metadata", path=path, mediainfo=mediainfo, + transfer_type=transfer_type, force_nfo=force_nfo, force_img=force_img) def register_commands(self, commands: Dict[str, dict]) -> None: """ diff --git a/app/modules/douban/__init__.py b/app/modules/douban/__init__.py index efbb9676..226df545 100644 --- a/app/modules/douban/__init__.py +++ b/app/modules/douban/__init__.py @@ -588,12 +588,15 @@ class DoubanModule(_ModuleBase): return [] return infos.get("subject_collection_items") - def scrape_metadata(self, path: Path, mediainfo: MediaInfo, transfer_type: str) -> None: + def scrape_metadata(self, path: Path, mediainfo: MediaInfo, transfer_type: str, + force_nfo: bool = False, force_img: bool = False) -> None: """ 刮削元数据 :param path: 媒体文件路径 :param mediainfo: 识别的媒体信息 :param transfer_type: 传输类型 + :param force_nfo: 是否强制刮削nfo + :param force_img: 是否强制刮削图片 :return: 成功或失败 """ if settings.SCRAP_SOURCE != "douban": @@ -630,7 +633,9 @@ class DoubanModule(_ModuleBase): self.scraper.gen_scraper_files(meta=meta, mediainfo=mediainfo, file_path=scrape_path, - transfer_type=transfer_type) + transfer_type=transfer_type, + force_nfo=force_nfo, + force_img=force_img) else: # 目录下的所有文件 for file in SystemUtils.list_files(path, settings.RMT_MEDIAEXT): @@ -667,7 +672,9 @@ class DoubanModule(_ModuleBase): self.scraper.gen_scraper_files(meta=meta, mediainfo=mediainfo, file_path=file, - transfer_type=transfer_type) + transfer_type=transfer_type, + force_nfo=force_nfo, + force_img=force_img) except Exception as e: logger.error(f"刮削文件 {file} 失败,原因:{str(e)}") logger.info(f"{path} 刮削完成") diff --git a/app/modules/douban/scraper.py b/app/modules/douban/scraper.py index 568fdc95..cd532592 100644 --- a/app/modules/douban/scraper.py +++ b/app/modules/douban/scraper.py @@ -14,53 +14,67 @@ from app.utils.system import SystemUtils class DoubanScraper: - _transfer_type = settings.TRANSFER_TYPE + _force_nfo = False + _force_img = False def gen_scraper_files(self, meta: MetaBase, mediainfo: MediaInfo, - file_path: Path, transfer_type: str): + file_path: Path, transfer_type: str, + force_nfo: bool = False, force_img: bool = False): """ 生成刮削文件 :param meta: 元数据 :param mediainfo: 媒体信息 :param file_path: 文件路径或者目录路径 :param transfer_type: 转输类型 + :param force_nfo: 强制生成NFO + :param force_img: 强制生成图片 """ self._transfer_type = transfer_type + self._force_nfo = force_nfo + self._force_img = force_img try: # 电影 if mediainfo.type == MediaType.MOVIE: # 强制或者不已存在时才处理 - if not file_path.with_name("movie.nfo").exists() \ - and not file_path.with_suffix(".nfo").exists(): + if self._force_nfo or (not file_path.with_name("movie.nfo").exists() + and not file_path.with_suffix(".nfo").exists()): # 生成电影描述文件 self.__gen_movie_nfo_file(mediainfo=mediainfo, file_path=file_path) # 生成电影图片 - self.__save_image(url=mediainfo.poster_path, - file_path=file_path.with_name(f"poster{Path(mediainfo.poster_path).suffix}")) + image_path = file_path.with_name(f"poster{Path(mediainfo.poster_path).suffix}") + if self._force_img or not image_path.exists(): + self.__save_image(url=mediainfo.poster_path, + file_path=image_path) # 背景图 if mediainfo.backdrop_path: - self.__save_image(url=mediainfo.backdrop_path, - file_path=file_path.with_name(f"backdrop{Path(mediainfo.backdrop_path).suffix}")) + image_path = file_path.with_name(f"backdrop{Path(mediainfo.backdrop_path).suffix}") + if self._force_img or not image_path.exists(): + self.__save_image(url=mediainfo.backdrop_path, + file_path=image_path) # 电视剧 else: # 不存在时才处理 - if not file_path.parent.with_name("tvshow.nfo").exists(): + if self._force_nfo or not file_path.parent.with_name("tvshow.nfo").exists(): # 根目录描述文件 self.__gen_tv_nfo_file(mediainfo=mediainfo, dir_path=file_path.parents[1]) # 生成根目录图片 - self.__save_image(url=mediainfo.poster_path, - file_path=file_path.with_name(f"poster{Path(mediainfo.poster_path).suffix}")) + image_path = file_path.with_name(f"poster{Path(mediainfo.poster_path).suffix}") + if self._force_img or not image_path.exists(): + self.__save_image(url=mediainfo.poster_path, + file_path=image_path) # 背景图 if mediainfo.backdrop_path: - self.__save_image(url=mediainfo.backdrop_path, - file_path=file_path.with_name(f"backdrop{Path(mediainfo.backdrop_path).suffix}")) + image_path = file_path.with_name(f"backdrop{Path(mediainfo.backdrop_path).suffix}") + if self._force_img or not image_path.exists(): + self.__save_image(url=mediainfo.backdrop_path, + file_path=image_path) # 季目录NFO - if not file_path.with_name("season.nfo").exists(): + if self._force_nfo or not file_path.with_name("season.nfo").exists(): self.__gen_tv_season_nfo_file(mediainfo=mediainfo, season=meta.begin_season, season_path=file_path.parent) @@ -175,8 +189,6 @@ class DoubanScraper: """ 下载图片并保存 """ - if file_path.exists(): - return if not url: return try: @@ -201,8 +213,6 @@ class DoubanScraper: """ 保存NFO """ - if file_path.exists(): - return xml_str = doc.toprettyxml(indent=" ", encoding="utf-8") if self._transfer_type in ['rclone_move', 'rclone_copy']: self.__save_remove_file(file_path, xml_str) diff --git a/app/modules/themoviedb/__init__.py b/app/modules/themoviedb/__init__.py index 3d49526d..f4d37709 100644 --- a/app/modules/themoviedb/__init__.py +++ b/app/modules/themoviedb/__init__.py @@ -212,12 +212,15 @@ class TheMovieDbModule(_ModuleBase): return [MediaInfo(tmdb_info=info) for info in results] - def scrape_metadata(self, path: Path, mediainfo: MediaInfo, transfer_type: str) -> None: + def scrape_metadata(self, path: Path, mediainfo: MediaInfo, transfer_type: str, + force_nfo: bool = False, force_img: bool = False) -> None: """ 刮削元数据 :param path: 媒体文件路径 :param mediainfo: 识别的媒体信息 :param transfer_type: 转移类型 + :param force_nfo: 强制刮削nfo + :param force_img: 强制刮削图片 :return: 成功或失败 """ if settings.SCRAP_SOURCE != "themoviedb": @@ -229,13 +232,17 @@ class TheMovieDbModule(_ModuleBase): scrape_path = path / path.name self.scraper.gen_scraper_files(mediainfo=mediainfo, file_path=scrape_path, - transfer_type=transfer_type) + transfer_type=transfer_type, + force_nfo=force_nfo, + force_img=force_img) elif path.is_file(): # 单个文件 logger.info(f"开始刮削媒体库文件:{path} ...") self.scraper.gen_scraper_files(mediainfo=mediainfo, file_path=path, - transfer_type=transfer_type) + transfer_type=transfer_type, + force_nfo=force_nfo, + force_img=force_img) else: # 目录下的所有文件 logger.info(f"开始刮削目录:{path} ...") @@ -244,7 +251,9 @@ class TheMovieDbModule(_ModuleBase): continue self.scraper.gen_scraper_files(mediainfo=mediainfo, file_path=file, - transfer_type=transfer_type) + transfer_type=transfer_type, + force_nfo=force_nfo, + force_img=force_img) logger.info(f"{path} 刮削完成") def tmdb_discover(self, mtype: MediaType, sort_by: str, with_genres: str, with_original_language: str, diff --git a/app/modules/themoviedb/scraper.py b/app/modules/themoviedb/scraper.py index 4e6d0cdb..49144bbf 100644 --- a/app/modules/themoviedb/scraper.py +++ b/app/modules/themoviedb/scraper.py @@ -19,19 +19,26 @@ from app.utils.system import SystemUtils class TmdbScraper: tmdb = None _transfer_type = settings.TRANSFER_TYPE + _force_nfo = False + _force_img = False def __init__(self, tmdb): self.tmdb = tmdb - def gen_scraper_files(self, mediainfo: MediaInfo, file_path: Path, transfer_type: str): + def gen_scraper_files(self, mediainfo: MediaInfo, file_path: Path, transfer_type: str, + force_nfo: bool = False, force_img: bool = False): """ 生成刮削文件,包括NFO和图片,传入路径为文件路径 :param mediainfo: 媒体信息 :param file_path: 文件路径或者目录路径 :param transfer_type: 传输类型 + :param force_nfo: 是否强制生成NFO + :param force_img: 是否强制生成图片 """ self._transfer_type = transfer_type + self._force_nfo = force_nfo + self._force_img = force_img def __get_episode_detail(_seasoninfo: dict, _episode: int): """ @@ -46,8 +53,8 @@ class TmdbScraper: # 电影,路径为文件名 名称/名称.xxx 或者蓝光原盘目录 名称/名称 if mediainfo.type == MediaType.MOVIE: # 不已存在时才处理 - if not file_path.with_name("movie.nfo").exists() \ - and not file_path.with_suffix(".nfo").exists(): + if self._force_nfo or (not file_path.with_name("movie.nfo").exists() + and not file_path.with_suffix(".nfo").exists()): # 生成电影描述文件 self.__gen_movie_nfo_file(mediainfo=mediainfo, file_path=file_path) @@ -59,14 +66,16 @@ class TmdbScraper: and isinstance(attr_value, str) \ and attr_value.startswith("http"): image_name = attr_name.replace("_path", "") + Path(attr_value).suffix - self.__save_image(url=attr_value, - file_path=file_path.with_name(image_name)) + image_path = file_path.with_name(image_name) + if self._force_img or not image_path.exists(): + self.__save_image(url=attr_value, + file_path=image_path) # 电视剧,路径为每一季的文件名 名称/Season xx/名称 SxxExx.xxx else: # 识别 meta = MetaInfo(file_path.stem) # 根目录不存在时才处理 - if not file_path.parent.with_name("tvshow.nfo").exists(): + if self._force_nfo or not file_path.parent.with_name("tvshow.nfo").exists(): # 根目录描述文件 self.__gen_tv_nfo_file(mediainfo=mediainfo, dir_path=file_path.parents[1]) @@ -79,13 +88,15 @@ class TmdbScraper: and isinstance(attr_value, str) \ and attr_value.startswith("http"): image_name = attr_name.replace("_path", "") + Path(attr_value).suffix - self.__save_image(url=attr_value, - file_path=file_path.parent.with_name(image_name)) + image_path = file_path.parent.with_name(image_name) + if self._force_img or not image_path.exists(): + self.__save_image(url=attr_value, + file_path=image_path) # 查询季信息 seasoninfo = self.tmdb.get_tv_season_detail(mediainfo.tmdb_id, meta.begin_season) if seasoninfo: # 季目录NFO - if not file_path.with_name("season.nfo").exists(): + if self._force_nfo or not file_path.with_name("season.nfo").exists(): self.__gen_tv_season_nfo_file(seasoninfo=seasoninfo, season=meta.begin_season, season_path=file_path.parent) @@ -96,7 +107,9 @@ class TmdbScraper: ext = Path(seasoninfo.get('poster_path')).suffix # URL url = f"https://{settings.TMDB_IMAGE_DOMAIN}/t/p/original{seasoninfo.get('poster_path')}" - self.__save_image(url, file_path.parent.with_name(f"season{sea_seq}-poster{ext}")) + image_path = file_path.parent.with_name(f"season{sea_seq}-poster{ext}") + if self._force_img or not image_path.exists(): + self.__save_image(url=url, file_path=image_path) # 季的其它图片 for attr_name, attr_value in vars(mediainfo).items(): if attr_value \ @@ -106,13 +119,15 @@ class TmdbScraper: and isinstance(attr_value, str) \ and attr_value.startswith("http"): image_name = attr_name.replace("_path", "") + Path(attr_value).suffix - self.__save_image(url=attr_value, - file_path=file_path.parent.with_name(image_name)) + image_path = file_path.parent.with_name(image_name) + if self._force_img or not image_path.exists(): + self.__save_image(url=attr_value, + file_path=image_path) # 查询集详情 episodeinfo = __get_episode_detail(seasoninfo, meta.begin_episode) if episodeinfo: # 集NFO - if not file_path.with_suffix(".nfo").exists(): + if self._force_nfo or not file_path.with_suffix(".nfo").exists(): self.__gen_tv_episode_nfo_file(episodeinfo=episodeinfo, tmdbid=mediainfo.tmdb_id, season=meta.begin_season, @@ -121,7 +136,7 @@ class TmdbScraper: # 集的图片 episode_image = episodeinfo.get("still_path") image_path = file_path.with_name(file_path.stem + "-thumb").with_suffix(Path(episode_image).suffix) - if episode_image: + if episode_image and (self._force_img or not image_path.exists()): self.__save_image( f"https://{settings.TMDB_IMAGE_DOMAIN}/t/p/original{episode_image}", image_path) @@ -340,8 +355,6 @@ class TmdbScraper: """ 下载图片并保存 """ - if file_path.exists(): - return try: logger.info(f"正在下载{file_path.stem}图片:{url} ...") r = RequestUtils().get_res(url=url, raise_exception=True) @@ -362,8 +375,6 @@ class TmdbScraper: """ 保存NFO """ - if file_path.exists(): - return xml_str = doc.toprettyxml(indent=" ", encoding="utf-8") if self._transfer_type in ['rclone_move', 'rclone_copy']: self.__save_remove_file(file_path, xml_str)