diff --git a/app/api/endpoints/category.py b/app/api/endpoints/category.py index 8859a3c7..771522c1 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().load_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/tmdb.py b/app/chain/tmdb.py index 0ed91550..c3c201f2 100644 --- a/app/chain/tmdb.py +++ b/app/chain/tmdb.py @@ -5,6 +5,7 @@ from app import schemas from app.chain import ChainBase from app.core.context import MediaInfo from app.schemas import MediaType +from app.schemas.category import CategoryConfig class TmdbChain(ChainBase): @@ -320,3 +321,15 @@ class TmdbChain(ChainBase): if infos: return [info.backdrop_path for info in infos if info and info.backdrop_path][:num] return [] + + def load_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) diff --git a/app/helper/category.py b/app/helper/category.py deleted file mode 100644 index bcdd80d4..00000000 --- a/app/helper/category.py +++ /dev/null @@ -1,58 +0,0 @@ -import yaml -from app.core.config import settings -from app.core.module import ModuleManager -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) - # 触发模块重新加载配置 - themoviedb_module = ModuleManager().get_running_module("TheMovieDbModule") - if themoviedb_module and hasattr(themoviedb_module, 'category'): - themoviedb_module.category.init() - logger.info("已触发分类配置重新加载") - 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..60e50244 100644 --- a/app/modules/themoviedb/category.py +++ b/app/modules/themoviedb/category.py @@ -1,4 +1,5 @@ import shutil +import yaml from pathlib import Path from typing import Union @@ -7,8 +8,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 +47,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 +60,38 @@ 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: + 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._category_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) + # 保存后重新加载配置 + 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: """