fix(download): respect configured directory priority (#7282)

This commit is contained in:
jxxghp
2026-11-03 13:11:17 +08:00
committed by GitHub
parent 91029be058
commit dc9eab695c
4 changed files with 93 additions and 3 deletions

View File

@@ -393,6 +393,18 @@ class DirectoryHelper:
"""
return sorted([d for d in self.get_dirs() if d.download_path], key=lambda x: x.priority or 0)
def get_download_dir(self, media: Optional[DirectoryMedia]) -> Optional[_SchemaTransferDirectoryConf]:
"""
按配置优先级返回首个媒体条件匹配且具有下载路径的目录。
类型和固定分类只用于过滤候选,不覆盖用户配置的优先级;同优先级保留配置顺序。
:param media: 待下载的影视或音乐媒体信息
:return: 首个可用下载目录,无匹配时返回 None
"""
return next((directory for directory in self.get_download_dirs()
if self.matches_media(directory, media)), None)
def get_local_download_dirs(self) -> List[_SchemaTransferDirectoryConf]:
"""
获取所有本地的可下载目录

View File

@@ -335,7 +335,11 @@ class DownloadSubtitleOwner(_DownloadOwnerBase):
save_path: Optional[str] = None,
) -> Tuple[Optional[str], Optional[Path], str]:
"""
根据媒体信息解析下载目录。
显式路径沿用原有校验与分类规则,默认路径按配置优先级选择可用下载目录。
:param media_info: 待下载媒体信息
:param save_path: 显式保存路径;空白值视为未指定
:return: 存储类型、保存目录及错误信息
"""
storage = 'local'
save_path = specified_download_save_path(save_path)
@@ -366,7 +370,7 @@ class DownloadSubtitleOwner(_DownloadOwnerBase):
)
return storage, target_dir, ""
dir_info = DirectoryHelper().get_dir(media_info, include_unsorted=True)
dir_info = DirectoryHelper().get_download_dir(media_info)
storage = (dir_info.storage or storage) if dir_info else storage
if not dir_info:
logger.error(f"未找到下载目录:{media_info.type.value if media_info.type else ""} {media_info.title_year}")

View File

@@ -189,6 +189,6 @@ def test_resolve_media_download_dir_uses_default_dir_for_blank_save_path():
"""
default_dir = TransferDirectoryConf(name="剧集库", priority=1, storage="local", download_path="/downloads/tv")
media = MediaInfo(type=MediaType.TV, title="测试剧集")
with patch.object(DirectoryHelper, "get_dir", return_value=default_dir):
with patch.object(DirectoryHelper, "get_download_dir", return_value=default_dir):
result = DownloadSubtitleOwner._resolve_media_download_dir(media, save_path="")
assert result == ("local", Path("/downloads/tv"), "")

View File

@@ -388,6 +388,80 @@ def test_directory_priority_applies_only_within_same_match_rank(
assert selected is high_priority
@pytest.mark.parametrize("save_path", [None, "", " "])
@pytest.mark.parametrize("fixed_category", [False, True])
def test_default_download_respects_priority_before_match_specificity(
directory_resolver: ClassificationCategoryResolver,
monkeypatch: pytest.MonkeyPatch,
save_path: str | None,
fixed_category: bool,
) -> None:
"""
未指定保存路径时,类型或固定分类更精确的目录不得盖过配置优先级。
"""
general = TransferDirectoryConf(
name="全部", priority=0, download_path="/downloads/all",
)
specific = TransferDirectoryConf(
name="电视剧", priority=1, media_type="tv", download_path="/downloads/tv",
media_category_id="tv.anime.jp" if fixed_category else None,
)
monkeypatch.setattr(
DirectoryHelper, "get_dirs", staticmethod(lambda: [specific, general]),
)
result = DownloadSubtitleOwner._resolve_media_download_dir(_media(), save_path)
assert result == ("local", Path("/downloads/all"), "")
@pytest.mark.parametrize(
"overrides",
[
{"download_path": None, "library_path": "/library"},
{"media_type": "movie"},
{"media_category_id": "tv.deleted"},
{"media_category": "其他"},
],
)
def test_default_download_skips_unavailable_or_mismatched_directories(
directory_resolver: ClassificationCategoryResolver,
monkeypatch: pytest.MonkeyPatch,
overrides: dict[str, object],
) -> None:
"""
高优先级目录缺少下载路径、类型分类不符或分类失效时,继续选择可用目录。
"""
invalid = TransferDirectoryConf.model_validate({
"priority": 0, "download_path": "/downloads/invalid", **overrides,
})
fallback = TransferDirectoryConf(priority=1, download_path="/downloads/fallback")
monkeypatch.setattr(
DirectoryHelper, "get_dirs", staticmethod(lambda: [invalid, fallback]),
)
assert DirectoryHelper(directory_resolver).get_download_dir(_media()) is fallback
monkeypatch.setattr(DirectoryHelper, "get_dirs", staticmethod(lambda: [invalid]))
assert DownloadSubtitleOwner._resolve_media_download_dir(_media()) == (
None, None, "未找到下载目录",
)
def test_default_download_preserves_configuration_order_for_equal_priority(
directory_resolver: ClassificationCategoryResolver,
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""
未设置和显式零优先级相同时,按配置顺序选择而非分类精确度。
"""
first = TransferDirectoryConf(download_path="/downloads/first")
second = TransferDirectoryConf(priority=0, media_type="tv", download_path="/downloads/second")
monkeypatch.setattr(
DirectoryHelper, "get_dirs", staticmethod(lambda: [first, second]),
)
assert DirectoryHelper(directory_resolver).get_download_dir(_media()) is first
def test_directory_media_type_aliases_match_consistently(
directory_resolver: ClassificationCategoryResolver,
) -> None: