Codex/fix season subscription poster (#6185)

This commit is contained in:
jxxghp
2026-07-25 08:07:08 +08:00
committed by GitHub
parent 6354a48405
commit ff9ba79b60
12 changed files with 439 additions and 38 deletions

View File

@@ -2,6 +2,8 @@ from pathlib import Path
from types import SimpleNamespace
from unittest.mock import MagicMock
import pytest
import app.chain.download as download_module
from app.chain.download import DownloadChain
from app.core.config import settings
@@ -11,6 +13,21 @@ from app.schemas import FileItem, NotExistMediaInfo, TransferDirectoryConf
from app.schemas.types import MediaType
@pytest.fixture(autouse=True)
def _mock_tmdb_supplement(monkeypatch):
"""隔离下载用例中的 TMDB 辅助识别外部边界。"""
class _NoopMediaChain:
"""保持原媒体对象不变的 TMDB 辅助识别替身。"""
@staticmethod
def supplement_tmdb_info(media, _meta):
"""返回原媒体对象。"""
return media
monkeypatch.setattr(download_module, "MediaChain", _NoopMediaChain)
class _FakeDownloadHistoryOper:
"""
避免单元测试写入真实下载历史,只验证下载链路的控制流。
@@ -176,6 +193,54 @@ def test_download_single_submits_download_added_to_background(monkeypatch):
)
def test_download_single_supplements_category_before_download_event(monkeypatch):
"""下载事件和目录选择前应已有 TMDB 分类,同时保留原识别源身份。"""
captured = {}
class _FakeMediaChain:
"""模拟 TMDB 辅助识别并记录调用。"""
@staticmethod
def supplement_tmdb_info(media, _meta):
"""给原媒体对象补充下载分类。"""
media.tmdb_id = 12345
media.category = "日本动画"
return media
def cancel_download(_event_type, event_data):
"""捕获下载事件后取消,避免进入真实下载流程。"""
captured["event_data"] = event_data
event_data.cancel = True
return SimpleNamespace(event_data=event_data)
monkeypatch.setattr(download_module, "MediaChain", _FakeMediaChain)
monkeypatch.setattr(download_module.eventmanager, "send_event", cancel_download)
media = MediaInfo(
source="bangumi",
media_id="40000",
bangumi_id=40000,
type=MediaType.TV,
title="测试动画",
)
context = Context(
meta_info=MetaInfo("测试动画 S01"),
media_info=media,
torrent_info=TorrentInfo(title="测试动画 S01"),
)
result = DownloadChain.__new__(DownloadChain).download_single(
context=context,
torrent_content="magnet:?xt=urn:btih:test",
return_detail=True,
)
assert result == (None, "下载被事件取消")
assert captured["event_data"].options["media_category"] == "日本动画"
assert context.media_info.source == "bangumi"
assert context.media_info.media_id == "40000"
assert context.media_info.tmdb_id == 12345
def test_download_single_persists_custom_words_snapshot(monkeypatch):
"""下载成功登记历史时,应把传入的订阅识别词原样存入快照,供整理时原样复现识别。"""
captured = {}

View File

@@ -18,6 +18,21 @@ from app.schemas import DownloaderTorrent, TransferDirectoryConf
from app.schemas.types import MediaType
@pytest.fixture(autouse=True)
def _mock_tmdb_supplement(monkeypatch):
"""隔离下载路径用例中的 TMDB 辅助识别外部边界。"""
class _NoopMediaChain:
"""保持原媒体对象不变的 TMDB 辅助识别替身。"""
@staticmethod
def supplement_tmdb_info(media, _meta):
"""返回原媒体对象。"""
return media
monkeypatch.setattr(download_module, "MediaChain", _NoopMediaChain)
def _download_dirs():
return [
TransferDirectoryConf(

View File

@@ -0,0 +1,112 @@
from types import SimpleNamespace
from app.chain.media import MediaChain
from app.core.context import MediaInfo
from app.core.metainfo import MetaInfo
from app.schemas.types import MediaType
class _FakeTmdbModule:
"""返回固定 TMDB 结果,避免测试访问外部元数据服务。"""
def __init__(self, result: MediaInfo):
"""保存测试需要返回的 TMDB 媒体信息。"""
self.result = result
def recognize_media(self, **_kwargs):
"""同步返回固定 TMDB 媒体信息。"""
return self.result
def _make_chain(tmdb_media: MediaInfo) -> MediaChain:
"""构造不加载真实模块的媒体处理链。"""
chain = object.__new__(MediaChain)
module = _FakeTmdbModule(tmdb_media)
chain.modulemanager = SimpleNamespace(
get_running_module=lambda module_id: (
module if module_id == "TheMovieDbModule" else None
)
)
return chain
def test_supplement_tmdb_keeps_custom_source_identity() -> None:
"""自定义识别源补充 TMDB 后,主身份和展示字段必须保持不变。"""
primary = MediaInfo(
source="plugin-anime",
media_id="subject-42",
type=MediaType.TV,
title="原识别标题",
year="2024",
category="",
)
tmdb_media = MediaInfo(
tmdb_info={
"id": 12345,
"media_type": MediaType.TV,
"name": "TMDB 标题",
"genre_ids": [16, 18],
"external_ids": {"imdb_id": "tt12345", "tvdb_id": 6789},
}
)
tmdb_media.category = "日本动画"
result = _make_chain(tmdb_media).supplement_tmdb_info(
primary, MetaInfo("原识别标题 2024")
)
assert result is primary
assert result.source == "plugin-anime"
assert result.media_id == "subject-42"
assert result.title == "原识别标题"
assert result.tmdb_id == 12345
assert result.genre_ids == [16, 18]
assert result.category == "日本动画"
def test_supplement_tmdb_does_not_override_custom_category() -> None:
"""下载历史或目录指定的自定义分类优先于 TMDB 自动分类。"""
primary = MediaInfo(
source="douban",
media_id="35593344",
douban_id="35593344",
type=MediaType.MOVIE,
title="测试电影",
category="纪录片",
)
tmdb_media = MediaInfo(
tmdb_info={
"id": 9876,
"media_type": MediaType.MOVIE,
"title": "Test Movie",
"genre_ids": [28],
}
)
tmdb_media.category = "动作片"
result = _make_chain(tmdb_media).supplement_tmdb_info(primary)
assert result.source == "douban"
assert result.media_id == "35593344"
assert result.category == "纪录片"
assert result.tmdb_id == 9876
def test_tmdb_supplement_uses_current_season_year_and_keeps_season_zero() -> None:
"""电视剧优先使用当前季年份,并且特别季季号不能退化为空。"""
media = MediaInfo(
source="bangumi",
media_id="42",
type=MediaType.TV,
title="测试动画",
year="2020",
season=0,
season_years={0: "2024"},
)
tmdb_meta = MediaChain._build_tmdb_supplement_meta(
media, MetaInfo("测试动画 S00 2020")
)
assert tmdb_meta.begin_season == 0
assert tmdb_meta.year == "2024"

View File

@@ -98,7 +98,8 @@ def test_conflicting_download_history_recognizes_movie_by_file_meta(monkeypatch)
lambda: SimpleNamespace(
recognize_by_meta=lambda meta, obtain_images: (
recognized_meta.append(meta) or fallback_media
)
),
supplement_tmdb_info=lambda media, _meta: media,
),
)
task = TransferTask(

View File

@@ -0,0 +1,56 @@
from types import SimpleNamespace
from app.chain.transfer import TransferChain
from app.core.context import MediaInfo
from app.core.metainfo import MetaInfo
from app.schemas import FileItem, TransferDirectoryConf, TransferTask
from app.schemas.types import MediaType
def test_transfer_stops_when_automatic_category_has_no_tmdb_result(monkeypatch) -> None:
"""启用自动类别目录时,缺少 TMDB 分类必须在文件操作前明确失败。"""
chain = object.__new__(TransferChain)
chain.jobview = SimpleNamespace(try_remove_job=lambda _task: None)
monkeypatch.setattr(
"app.chain.transfer.TransferHistoryOper",
lambda: SimpleNamespace(),
)
monkeypatch.setattr(
"app.chain.transfer.MediaChain",
lambda: SimpleNamespace(
supplement_tmdb_info=lambda media, _meta: media,
),
)
task = TransferTask(
fileitem=FileItem(
storage="local",
path="/downloads/Test.Movie.2024.mkv",
type="file",
name="Test.Movie.2024.mkv",
extension="mkv",
size=1024,
),
meta=MetaInfo("Test Movie 2024"),
mediainfo=MediaInfo(
source="anilist",
media_id="1234",
anilist_id=1234,
type=MediaType.MOVIE,
title="Test Movie",
year="2024",
),
target_directory=TransferDirectoryConf(
library_storage="local",
library_path="/library",
library_category_folder=True,
),
library_category_folder=True,
preview=True,
)
state, message = chain._TransferChain__handle_transfer(task)
assert not state
assert message == "未识别到 TMDB 辅助信息,无法按媒体类别整理"
assert task.mediainfo.source == "anilist"
assert task.mediainfo.media_id == "1234"