mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-05-24 07:26:50 +00:00
206 lines
7.7 KiB
Python
206 lines
7.7 KiB
Python
import asyncio
|
|
from unittest import TestCase
|
|
from unittest.mock import AsyncMock, Mock, patch
|
|
|
|
from app.core.context import MediaInfo
|
|
from app.core.meta import MetaBase
|
|
from app.modules.douban import DoubanModule
|
|
from app.modules.themoviedb import TheMovieDbModule
|
|
from app.modules.themoviedb.scraper import TmdbScraper
|
|
from app.modules.themoviedb.tmdbapi import TmdbApi
|
|
from app.schemas.types import MediaType
|
|
|
|
|
|
class MediaRecognizeModulesTest(TestCase):
|
|
def test_tmdb_cache_false_skips_cache_lookup(self):
|
|
"""cache=False 时应跳过缓存读取,但仍按正常流程查询 TMDB。"""
|
|
module = TheMovieDbModule()
|
|
meta = MetaBase("测试电影")
|
|
meta.name = "测试电影"
|
|
meta.type = MediaType.MOVIE
|
|
module.cache = Mock()
|
|
module.tmdb = Mock()
|
|
module.tmdb.get_info.return_value = {
|
|
"id": 100,
|
|
"media_type": MediaType.MOVIE,
|
|
"title": "测试电影",
|
|
"genres": [],
|
|
}
|
|
module.category = Mock()
|
|
module.category.get_movie_category.return_value = None
|
|
|
|
result = module.recognize_media(meta=meta, tmdbid=100, cache=False)
|
|
|
|
self.assertIsInstance(result, MediaInfo)
|
|
self.assertEqual(result.tmdb_id, 100)
|
|
module.cache.get.assert_not_called()
|
|
module.cache.update.assert_called_once()
|
|
|
|
def test_async_tmdb_cache_false_skips_cache_lookup(self):
|
|
"""异步 cache=False 时也应跳过缓存读取。"""
|
|
module = TheMovieDbModule()
|
|
meta = MetaBase("测试电影")
|
|
meta.name = "测试电影"
|
|
meta.type = MediaType.MOVIE
|
|
module.cache = Mock()
|
|
module.tmdb = Mock()
|
|
|
|
async def _async_get_info(**kwargs):
|
|
return {
|
|
"id": 101,
|
|
"media_type": MediaType.MOVIE,
|
|
"title": "测试电影",
|
|
"genres": [],
|
|
}
|
|
|
|
module.tmdb.async_get_info = _async_get_info
|
|
module.category = Mock()
|
|
module.category.get_movie_category.return_value = None
|
|
|
|
result = asyncio.run(module.async_recognize_media(meta=meta, tmdbid=101, cache=False))
|
|
|
|
self.assertIsInstance(result, MediaInfo)
|
|
self.assertEqual(result.tmdb_id, 101)
|
|
module.cache.get.assert_not_called()
|
|
module.cache.update.assert_called_once()
|
|
|
|
def test_tmdb_recognize_does_not_fallback_to_match_web(self):
|
|
"""TMDB API 搜索无结果时,不应再回退抓取 TMDB 网站搜索页。"""
|
|
module = TheMovieDbModule()
|
|
meta = MetaBase("No Match Movie")
|
|
meta.name = "No Match Movie"
|
|
meta.type = MediaType.MOVIE
|
|
module.cache = Mock()
|
|
module.tmdb = Mock()
|
|
module.tmdb.match_web.side_effect = AssertionError("不应调用 TMDB 网站搜索")
|
|
module._search_by_name = Mock(return_value=None)
|
|
|
|
result = module.recognize_media(meta=meta, cache=False)
|
|
|
|
self.assertIsNone(result)
|
|
module._search_by_name.assert_called()
|
|
module.tmdb.match_web.assert_not_called()
|
|
|
|
def test_async_tmdb_recognize_does_not_fallback_to_match_web(self):
|
|
"""异步 TMDB API 搜索无结果时,不应再回退抓取 TMDB 网站搜索页。"""
|
|
module = TheMovieDbModule()
|
|
meta = MetaBase("No Match Movie")
|
|
meta.name = "No Match Movie"
|
|
meta.type = MediaType.MOVIE
|
|
module.cache = Mock()
|
|
module.tmdb = Mock()
|
|
module.tmdb.async_match_web = AsyncMock(side_effect=AssertionError("不应调用 TMDB 网站搜索"))
|
|
module._async_search_by_name = AsyncMock(return_value=None)
|
|
|
|
result = asyncio.run(module.async_recognize_media(meta=meta, cache=False))
|
|
|
|
self.assertIsNone(result)
|
|
module._async_search_by_name.assert_called()
|
|
module.tmdb.async_match_web.assert_not_called()
|
|
|
|
def test_tmdb_image_language_fallback_includes_current_en_null_and_original(self):
|
|
"""TMDB 图片查询应带上语言回退,避免当前语言没有图片时直接返回空。"""
|
|
with patch("app.modules.themoviedb.tmdbapi.settings") as mock_settings:
|
|
mock_settings.TMDB_LOCALE = "zh"
|
|
|
|
result = TmdbApi._build_include_image_language("ja")
|
|
|
|
self.assertEqual(result, "zh,en,null,ja")
|
|
|
|
def test_tmdb_obtain_images_uses_language_fallback_and_picks_best(self):
|
|
"""obtain_images 应从图片接口回填缺失的海报和背景图。"""
|
|
module = TheMovieDbModule()
|
|
module.tmdb = Mock()
|
|
module.tmdb.get_movie_images.return_value = {
|
|
"posters": [
|
|
{"file_path": "/low-poster.jpg", "vote_average": 2, "vote_count": 10},
|
|
{"file_path": "/best-poster.jpg", "vote_average": 8, "vote_count": 1},
|
|
],
|
|
"backdrops": [
|
|
{"file_path": "/best-backdrop.jpg", "vote_average": 7, "vote_count": 2},
|
|
],
|
|
}
|
|
mediainfo = MediaInfo(
|
|
tmdb_id=100,
|
|
type=MediaType.MOVIE,
|
|
original_language="ja",
|
|
)
|
|
|
|
result = module.obtain_images(mediainfo)
|
|
|
|
self.assertIs(result, mediainfo)
|
|
module.tmdb.get_movie_images.assert_called_once_with(100, original_language="ja")
|
|
self.assertTrue(mediainfo.poster_path.endswith("/best-poster.jpg"))
|
|
self.assertTrue(mediainfo.backdrop_path.endswith("/best-backdrop.jpg"))
|
|
|
|
def test_tmdb_scraper_metadata_img_fetches_missing_main_images(self):
|
|
"""主媒体图片缺失时,刮削图片列表应先从 TMDB images 接口补齐。"""
|
|
scraper = TmdbScraper()
|
|
scraper._meta_tmdb = Mock()
|
|
scraper._meta_tmdb.get_movie_images.return_value = {
|
|
"posters": [
|
|
{"file_path": "/fallback-poster.jpg", "vote_average": 5},
|
|
],
|
|
"backdrops": [
|
|
{"file_path": "/fallback-backdrop.jpg", "vote_average": 4},
|
|
],
|
|
}
|
|
mediainfo = MediaInfo(
|
|
tmdb_id=200,
|
|
type=MediaType.MOVIE,
|
|
original_language="en",
|
|
)
|
|
|
|
images = scraper.get_metadata_img(mediainfo)
|
|
|
|
scraper._meta_tmdb.get_movie_images.assert_called_once_with(
|
|
200,
|
|
original_language="en",
|
|
)
|
|
self.assertIn("poster.jpg", images)
|
|
self.assertIn("backdrop.jpg", images)
|
|
|
|
def test_douban_prepare_search_names_deduplicates_simplified_name(self):
|
|
"""豆瓣候选名称应保留顺序,并去掉繁简转换后的重复项。"""
|
|
meta = MetaBase("流浪地球")
|
|
meta.cn_name = "流浪地球"
|
|
meta.en_name = "The Wandering Earth"
|
|
|
|
self.assertEqual(
|
|
DoubanModule._prepare_search_names(meta),
|
|
["流浪地球", "The Wandering Earth"],
|
|
)
|
|
|
|
def test_douban_search_result_helper_preserves_season_title_rule(self):
|
|
"""豆瓣搜索结果 helper 应保留电视剧标题追加季号的旧逻辑。"""
|
|
meta = MetaBase("测试剧")
|
|
meta.name = "测试剧"
|
|
meta.type = MediaType.TV
|
|
meta.begin_season = 2
|
|
items = [
|
|
{
|
|
"type_name": MediaType.TV.value,
|
|
"target": {
|
|
"id": "200",
|
|
"title": "测试剧",
|
|
"type": "tv",
|
|
"year": "2024",
|
|
},
|
|
},
|
|
{
|
|
"type_name": MediaType.MOVIE.value,
|
|
"target": {
|
|
"id": "201",
|
|
"title": "测试剧 电影版",
|
|
"type": "movie",
|
|
"year": "2024",
|
|
},
|
|
},
|
|
]
|
|
|
|
result = DoubanModule._build_search_medias_result(meta, items)
|
|
|
|
self.assertEqual(len(result), 1)
|
|
self.assertEqual(result[0].title, "测试剧 第二季")
|
|
self.assertEqual(result[0].season, 2)
|