Files
MoviePilot/tests/test_download_media_source.py
DDSRem 2de976f6b3 Merge pull request #7050 from DDSRem-Dev/codex-comment-migration
docs: 统一全项目中文注释和结构化契约说明
2026-10-17 19:26:29 +08:00

223 lines
7.4 KiB
Python

"""
验证下载提交传递通用媒体来源,并校验标识和人工确认。
"""
from types import SimpleNamespace
from unittest.mock import Mock
from app import schemas
from app.api.endpoints import download as download_endpoint
from app.domain.context import MediaInfo
from app.schemas.types import MediaSource, MediaType
def test_download_add_passes_generic_media_source(monkeypatch) -> None:
"""
不含媒体信息的下载应按统一来源ID执行精确识别。
"""
captured = {}
media = MediaInfo(
anilist_info={
"id": 154587,
"title": {"english": "Frieren"},
"format": "TV",
}
)
class FakeMediaChain:
"""
记录下载接口传入的媒体识别参数。
"""
def recognize_media(self, **kwargs):
"""
返回固定媒体信息并保存识别参数。
"""
captured["recognize"] = kwargs
return media
class FakeDownloadChain:
"""
模拟下载任务提交。
"""
def download_single(self, **kwargs):
"""
保存下载上下文并返回任务ID。
"""
captured["download"] = kwargs
return "download-1"
monkeypatch.setattr(download_endpoint, "MediaChain", FakeMediaChain)
monkeypatch.setattr(download_endpoint, "DownloadChain", FakeDownloadChain)
response = download_endpoint.add(
torrent_in=schemas.TorrentInfo(title="Frieren S01E01"),
media_source="anilist",
media_id="154587",
current_user=SimpleNamespace(name="tester"),
)
assert response.success is True
assert captured["recognize"]["media_source"] == MediaSource.AniList
assert captured["recognize"]["media_id"] == "154587"
assert captured["download"]["context"].media_info is media
def test_download_add_rejects_source_without_media_id() -> None:
"""
显式媒体来源必须和原生 ID 成对提供,不能退回标题猜测。
"""
response = download_endpoint.add(
torrent_in=schemas.TorrentInfo(title="测试动画 S01E01"),
media_source="bangumi",
current_user=SimpleNamespace(name="tester"),
)
assert response.success is False
assert response.message == "媒体来源和媒体 ID 必须同时提供"
def test_download_add_requires_confirmation_when_recognition_fails(monkeypatch) -> None:
"""
未识别的影视资源必须先由用户确认,不能直接提交下载。
"""
media_chain = Mock()
media_chain.recognize_by_meta.return_value = None
download_chain = Mock()
monkeypatch.setattr(download_endpoint, "MediaChain", lambda: media_chain)
monkeypatch.setattr(download_endpoint, "DownloadChain", lambda: download_chain)
response = download_endpoint.add(
torrent_in=schemas.TorrentInfo(
title="Harry Potter Complete Collection",
category=MediaType.MOVIE.value,
),
current_user=SimpleNamespace(name="tester"),
)
assert response.success is False
assert response.message == "无法识别媒体信息"
assert response.data.requires_confirmation is True
download_chain.download_single.assert_not_called()
def test_download_add_allows_confirmed_unrecognized_video(monkeypatch) -> None:
"""
用户确认后应使用种子元数据提交未识别的影视合集。
"""
media_chain = Mock()
media_chain.recognize_by_meta.return_value = None
download_chain = Mock()
download_chain.download_single.return_value = "download-collection"
monkeypatch.setattr(download_endpoint, "MediaChain", lambda: media_chain)
monkeypatch.setattr(download_endpoint, "DownloadChain", lambda: download_chain)
response = download_endpoint.add(
torrent_in=schemas.TorrentInfo(
title="Harry Potter Complete Collection",
category="movie",
),
allow_unrecognized=True,
current_user=SimpleNamespace(name="tester"),
)
assert response.success is True
context = download_chain.download_single.call_args.kwargs["context"]
assert context.media_info.type == MediaType.MOVIE
assert context.media_info.title == "Harry Potter Complete Collection"
assert context.media_info.media_id is None
def test_download_add_requires_confirmation_for_unrecognized_music(monkeypatch) -> None:
"""
未识别的音乐资源同样需要先由用户确认,不能直接提交下载。
"""
media_chain = Mock()
media_chain.recognize_by_meta.return_value = None
download_chain = Mock()
monkeypatch.setattr(download_endpoint, "MediaChain", lambda: media_chain)
monkeypatch.setattr(download_endpoint, "DownloadChain", lambda: download_chain)
response = download_endpoint.add(
torrent_in=schemas.TorrentInfo(
title="Various Artists - 90s Collection",
category=MediaType.MUSIC.value,
),
music_type="album",
current_user=SimpleNamespace(name="tester"),
)
assert response.success is False
assert response.message == "无法识别媒体信息"
assert response.data.requires_confirmation is True
download_chain.download_single.assert_not_called()
def test_download_add_allows_confirmed_unrecognized_music(monkeypatch) -> None:
"""
用户确认后音乐资源也应使用种子元数据继续下载。
"""
media_chain = Mock()
media_chain.recognize_by_meta.return_value = None
download_chain = Mock()
download_chain.download_single.return_value = "download-music"
monkeypatch.setattr(download_endpoint, "MediaChain", lambda: media_chain)
monkeypatch.setattr(download_endpoint, "DownloadChain", lambda: download_chain)
response = download_endpoint.add(
torrent_in=schemas.TorrentInfo(
title="Various Artists - 90s Collection",
category="music",
),
music_type="album",
allow_unrecognized=True,
current_user=SimpleNamespace(name="tester"),
)
assert response.success is True
context = download_chain.download_single.call_args.kwargs["context"]
assert context.media_info.type == MediaType.MUSIC
assert context.media_info.music_type == "album"
assert context.media_info.title == "90s Collection"
def test_subtitle_download_passes_generic_media_source(monkeypatch) -> None:
"""
字幕下载接口应把统一来源ID传递到下载链。
"""
captured = {}
class FakeDownloadChain:
"""
记录字幕下载参数。
"""
def download_subtitle(self, **kwargs):
"""
保存参数并返回固定成功结果。
"""
captured.update(kwargs)
return True, "字幕下载成功", ["/tmp/subtitle.ass"]
monkeypatch.setattr(
download_endpoint,
"_prepare_subtitle_download",
lambda _subtitle: (True, ""),
)
monkeypatch.setattr(download_endpoint, "DownloadChain", FakeDownloadChain)
response = download_endpoint.download_subtitle(
subtitle_in=schemas.SubtitleInfo(
title="Frieren S01E01",
enclosure="https://example.com/subtitle.ass",
),
media_source="anilist",
media_id="154587",
current_user=SimpleNamespace(name="tester"),
)
assert response.success is True
assert captured["media_source"] == "anilist"
assert captured["media_id"] == "154587"