diff --git a/app/helper/directory.py b/app/helper/directory.py index ee95ad40ee..c40695a1f3 100644 --- a/app/helper/directory.py +++ b/app/helper/directory.py @@ -74,7 +74,8 @@ def get_download_dir_by_save_path( return dir_info if dir_info.media_type == media_type and not dir_info.media_category: return dir_info - if dir_info.media_type == media_type and dir_info.media_category == media.category: + if dir_info.media_type == media_type and _match_media_category( + dir_info.media_category, media.category): return dir_info return None @@ -136,8 +137,8 @@ def get_dir(self, media: Optional[MediaInfo], include_unsorted: Optional[bool] = if d.media_type == media_type and not d.media_category: matched_dirs.append(d) continue - # 目录类型相等,目录类别相等,符合条件 - if d.media_type == media_type and d.media_category == media.category: + # 目录类型相等,目录类别命中配置,符合条件 + if d.media_type == media_type and _match_media_category(d.media_category, media.category): matched_dirs.append(d) continue if matched_dirs: @@ -210,6 +211,20 @@ def get_media_root_path(rename_format: str, rename_path: Path) -> Optional[Path] return media_root +def _match_media_category(configured_category: Optional[str], media_category: Optional[str]) -> bool: + """ + 判断媒体类别是否命中目录配置,支持逗号分隔的多个类别。 + """ + if not configured_category or not media_category: + return False + categories = { + category.strip() + for category in re.split(r"[,,]", configured_category) + if category.strip() + } + return media_category.strip() in categories + + def _split_file_uri(value: str) -> Tuple[str, str]: """ 拆分 FileURI 字符串,保留原始路径用于安全校验。 diff --git a/tests/test_directory.py b/tests/test_directory.py new file mode 100644 index 0000000000..37880b16f8 --- /dev/null +++ b/tests/test_directory.py @@ -0,0 +1,72 @@ +from pathlib import Path +from types import SimpleNamespace + +import pytest + +from app.helper.directory import DirectoryHelper +from app.schemas import TransferDirectoryConf + + +def _media(category: str): + """构造目录匹配测试所需的媒体信息。""" + return SimpleNamespace( + type=SimpleNamespace(value="电视剧"), + category=category, + ) + + +def _directory(media_category: str) -> TransferDirectoryConf: + """构造启用自动整理的动漫目录配置。""" + return TransferDirectoryConf( + name="动漫", + priority=1, + storage="local", + download_path="/media/anime", + media_type="电视剧", + media_category=media_category, + monitor_type="monitor", + library_path="/media/link/anime", + library_storage="local", + ) + + +@pytest.mark.parametrize("configured_category", ["日番", "日番,日韩剧", "日番,日韩剧", " 日番 , 日韩剧 "]) +def test_get_dir_matches_media_category_list(monkeypatch, configured_category): + """自动整理应匹配目录配置中逗号分隔的任一媒体类别。""" + directory = _directory(configured_category) + monkeypatch.setattr(DirectoryHelper, "get_dirs", staticmethod(lambda: [directory])) + + matched = DirectoryHelper().get_dir( + media=_media("日番"), + storage="local", + src_path=Path("/media/anime/demo.mkv"), + ) + + assert matched == directory + + +def test_get_dir_rejects_unconfigured_media_category(monkeypatch): + """自动整理不应匹配目录配置中不存在的媒体类别。""" + directory = _directory("日番,日韩剧") + monkeypatch.setattr(DirectoryHelper, "get_dirs", staticmethod(lambda: [directory])) + + matched = DirectoryHelper().get_dir( + media=_media("欧美剧"), + storage="local", + src_path=Path("/media/anime/demo.mkv"), + ) + + assert matched is None + + +def test_get_download_dir_by_save_path_matches_media_category_list(monkeypatch): + """精确保存根路径应继承逗号分隔的媒体类别规则。""" + directory = _directory("日番,日韩剧") + monkeypatch.setattr(DirectoryHelper, "get_download_dirs", lambda _self: [directory]) + + matched = DirectoryHelper().get_download_dir_by_save_path( + media=_media("日韩剧"), + save_path="/media/anime", + ) + + assert matched == directory