diff --git a/app/api/endpoints/category.py b/app/api/endpoints/category.py index 8859a3c7..5f6d6977 100644 --- a/app/api/endpoints/category.py +++ b/app/api/endpoints/category.py @@ -1,8 +1,8 @@ from fastapi import APIRouter, Depends from app import schemas +from app.chain.tmdb import TmdbChain from app.db.models import User from app.db.user_oper import get_current_active_superuser, get_current_active_user -from app.helper.category import CategoryHelper from app.schemas.category import CategoryConfig router = APIRouter() @@ -13,7 +13,7 @@ def get_category_config(_: User = Depends(get_current_active_user)): """ 获取分类策略配置 """ - config = CategoryHelper().load() + config = TmdbChain().category_config() return schemas.Response(success=True, data=config.model_dump()) @@ -22,7 +22,7 @@ def save_category_config(config: CategoryConfig, _: User = Depends(get_current_a """ 保存分类策略配置 """ - if CategoryHelper().save(config): + if TmdbChain().save_category_config(config): return schemas.Response(success=True, message="保存成功") else: return schemas.Response(success=False, message="保存失败") diff --git a/app/chain/__init__.py b/app/chain/__init__.py index 098fc951..f8a2aebd 100644 --- a/app/chain/__init__.py +++ b/app/chain/__init__.py @@ -26,6 +26,7 @@ from app.helper.service import ServiceConfigHelper from app.log import logger from app.schemas import TransferInfo, TransferTorrent, ExistMediaInfo, DownloadingTorrent, CommingMessage, Notification, \ WebhookEventInfo, TmdbEpisode, MediaPerson, FileItem, TransferDirectoryConf +from app.schemas.category import CategoryConfig from app.schemas.types import TorrentStatus, MediaType, MediaImageType, EventType, MessageChannel from app.utils.object import ObjectUtils @@ -1062,6 +1063,18 @@ class ChainBase(metaclass=ABCMeta): """ return self.run_module("media_category") + def category_config(self) -> CategoryConfig: + """ + 获取分类策略配置 + """ + return self.run_module("load_category_config") + + def save_category_config(self, config: CategoryConfig) -> bool: + """ + 保存分类策略配置 + """ + return self.run_module("save_category_config", config=config) + def register_commands(self, commands: Dict[str, dict]) -> None: """ 注册菜单命令 diff --git a/app/helper/category.py b/app/helper/category.py deleted file mode 100644 index 9bf23e18..00000000 --- a/app/helper/category.py +++ /dev/null @@ -1,52 +0,0 @@ -import yaml -from app.core.config import settings -from app.log import logger -from app.schemas.category import CategoryConfig - -HEADER_COMMENTS = """####### 配置说明 ####### -# 1. 该配置文件用于配置电影和电视剧的分类策略,配置后程序会按照配置的分类策略名称进行分类,配置文件采用yaml格式,需要严格附合语法规则 -# 2. 配置文件中的一级分类名称:`movie`、`tv` 为固定名称不可修改,二级名称同时也是目录名称,会按先后顺序匹配,匹配后程序会按这个名称建立二级目录 -# 3. 支持的分类条件: -# `original_language` 语种,具体含义参考下方字典 -# `production_countries` 国家或地区(电影)、`origin_country` 国家或地区(电视剧),具体含义参考下方字典 -# `genre_ids` 内容类型,具体含义参考下方字典 -# `release_year` 发行年份,格式:YYYY,电影实际对应`release_date`字段,电视剧实际对应`first_air_date`字段,支持范围设定,如:`YYYY-YYYY` -# themoviedb 详情API返回的其它一级字段 -# 4. 配置多项条件时需要同时满足,一个条件需要匹配多个值是使用`,`分隔 -# 5. !条件值表示排除该值 - -""" - -class CategoryHelper: - def __init__(self): - self._config_path = settings.CONFIG_PATH / 'category.yaml' - - def load(self) -> CategoryConfig: - """ - 加载配置 - """ - config = CategoryConfig() - if not self._config_path.exists(): - return config - try: - with open(self._config_path, 'r', encoding='utf-8') as f: - data = yaml.safe_load(f) - if data: - config = CategoryConfig(**data) - except Exception as e: - logger.error(f"Load category config failed: {e}") - return config - - def save(self, config: CategoryConfig) -> bool: - """ - 保存配置 - """ - data = config.model_dump(exclude_none=True) - try: - with open(self._config_path, 'w', encoding='utf-8') as f: - f.write(HEADER_COMMENTS) - yaml.dump(data, f, allow_unicode=True, sort_keys=False, default_flow_style=False) - return True - except Exception as e: - logger.error(f"Save category config failed: {e}") - return False diff --git a/app/modules/themoviedb/__init__.py b/app/modules/themoviedb/__init__.py index 5e5832d2..4cfd494d 100644 --- a/app/modules/themoviedb/__init__.py +++ b/app/modules/themoviedb/__init__.py @@ -14,10 +14,12 @@ from app.modules.themoviedb.category import CategoryHelper from app.modules.themoviedb.scraper import TmdbScraper from app.modules.themoviedb.tmdb_cache import TmdbCache from app.modules.themoviedb.tmdbapi import TmdbApi +from app.schemas.category import CategoryConfig from app.schemas.types import MediaType, MediaImageType, ModuleType, MediaRecognizeType from app.utils.http import RequestUtils + class TheMovieDbModule(_ModuleBase): """ TMDB媒体信息匹配 @@ -1290,3 +1292,15 @@ class TheMovieDbModule(_ModuleBase): self.tmdb.clear_cache() self.cache.clear() logger.info("TMDB缓存清除完成") + + def load_category_config(self) -> CategoryConfig: + """ + 加载分类配置 + """ + return self.category.load() + + def save_category_config(self, config: CategoryConfig) -> bool: + """ + 保存分类配置 + """ + return self.category.save(config) diff --git a/app/modules/themoviedb/category.py b/app/modules/themoviedb/category.py index 387c0d9c..99e7104a 100644 --- a/app/modules/themoviedb/category.py +++ b/app/modules/themoviedb/category.py @@ -7,8 +7,23 @@ from ruamel.yaml import CommentedMap from app.core.config import settings from app.log import logger +from app.schemas.category import CategoryConfig from app.utils.singleton import WeakSingleton +HEADER_COMMENTS = """####### 配置说明 ####### +# 1. 该配置文件用于配置电影和电视剧的分类策略,配置后程序会按照配置的分类策略名称进行分类,配置文件采用yaml格式,需要严格符合语法规则 +# 2. 配置文件中的一级分类名称:`movie`、`tv` 为固定名称不可修改,二级名称同时也是目录名称,会按先后顺序匹配,匹配后程序会按这个名称建立二级目录 +# 3. 支持的分类条件: +# `original_language` 语种,具体含义参考下方字典 +# `production_countries` 国家或地区(电影)、`origin_country` 国家或地区(电视剧),具体含义参考下方字典 +# `genre_ids` 内容类型,具体含义参考下方字典 +# `release_year` 发行年份,格式:YYYY,电影实际对应`release_date`字段,电视剧实际对应`first_air_date`字段,支持范围设定,如:`YYYY-YYYY` +# themoviedb 详情API返回的其它一级字段 +# 4. 配置多项条件时需要同时满足,一个条件需要匹配多个值是使用`,`分隔 +# 5. !条件值表示排除该值 + +""" + class CategoryHelper(metaclass=WeakSingleton): """ @@ -31,8 +46,8 @@ class CategoryHelper(metaclass=WeakSingleton): shutil.copy(settings.INNER_CONFIG_PATH / "category.yaml", self._category_path) with open(self._category_path, mode='r', encoding='utf-8') as f: try: - yaml = ruamel.yaml.YAML() - self._categorys = yaml.load(f) + yaml_loader = ruamel.yaml.YAML() + self._categorys = yaml_loader.load(f) except Exception as e: logger.warn(f"二级分类策略配置文件格式出现严重错误!请检查:{str(e)}") self._categorys = {} @@ -44,6 +59,40 @@ class CategoryHelper(metaclass=WeakSingleton): self._tv_categorys = self._categorys.get('tv') logger.info(f"已加载二级分类策略 category.yaml") + def load(self) -> CategoryConfig: + """ + 加载配置 + """ + config = CategoryConfig() + if not self._category_path.exists(): + return config + try: + with open(self._category_path, 'r', encoding='utf-8') as f: + yaml_loader = ruamel.yaml.YAML() + data = yaml_loader.load(f) + if data: + config = CategoryConfig(**data) + except Exception as e: + logger.error(f"Load category config failed: {e}") + return config + + def save(self, config: CategoryConfig) -> bool: + """ + 保存配置 + """ + data = config.model_dump(exclude_none=True) + try: + with open(self._category_path, 'w', encoding='utf-8') as f: + f.write(HEADER_COMMENTS) + yaml_dumper = ruamel.yaml.YAML() + yaml_dumper.dump(data, f) + # 保存后重新加载配置 + self.init() + return True + except Exception as e: + logger.error(f"Save category config failed: {e}") + return False + @property def is_movie_category(self) -> bool: """