Fix NFO plot fallback by using en-US search overview when German result is empty
This commit is contained in:
@@ -174,6 +174,32 @@ class NFOService:
|
|||||||
# Enrich with fallback languages for empty overview/tagline
|
# Enrich with fallback languages for empty overview/tagline
|
||||||
# Pass search result overview as last resort fallback
|
# Pass search result overview as last resort fallback
|
||||||
search_overview = tv_show.get("overview") or None
|
search_overview = tv_show.get("overview") or None
|
||||||
|
if not search_overview:
|
||||||
|
try:
|
||||||
|
logger.debug(
|
||||||
|
"No overview in German search result, trying en-US search fallback for: %s",
|
||||||
|
search_name,
|
||||||
|
)
|
||||||
|
en_search_results = await self.tmdb_client.search_tv_show(
|
||||||
|
search_name,
|
||||||
|
language="en-US",
|
||||||
|
)
|
||||||
|
if en_search_results.get("results"):
|
||||||
|
en_match = self._find_best_match(
|
||||||
|
en_search_results["results"], search_name, year
|
||||||
|
)
|
||||||
|
search_overview = en_match.get("overview") or None
|
||||||
|
if search_overview:
|
||||||
|
logger.info(
|
||||||
|
"Using en-US search overview fallback for %s",
|
||||||
|
search_name,
|
||||||
|
)
|
||||||
|
except (TMDBAPIError, Exception) as exc:
|
||||||
|
logger.warning(
|
||||||
|
"Failed en-US search fallback for overview: %s",
|
||||||
|
exc,
|
||||||
|
)
|
||||||
|
|
||||||
details = await self._enrich_details_with_fallback(
|
details = await self._enrich_details_with_fallback(
|
||||||
details, search_overview=search_overview
|
details, search_overview=search_overview
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -424,7 +424,14 @@ class TestCreateTVShowNFO:
|
|||||||
patch.object(nfo_service.tmdb_client, 'get_tv_show_content_ratings', new_callable=AsyncMock) as mock_ratings, \
|
patch.object(nfo_service.tmdb_client, 'get_tv_show_content_ratings', new_callable=AsyncMock) as mock_ratings, \
|
||||||
patch.object(nfo_service, '_download_media_files', new_callable=AsyncMock):
|
patch.object(nfo_service, '_download_media_files', new_callable=AsyncMock):
|
||||||
|
|
||||||
mock_search.return_value = {"results": [{"id": 1429, "name": "Attack on Titan", "first_air_date": "2013-04-07"}]}
|
mock_search.return_value = {
|
||||||
|
"results": [{
|
||||||
|
"id": 1429,
|
||||||
|
"name": "Attack on Titan",
|
||||||
|
"first_air_date": "2013-04-07",
|
||||||
|
"overview": "Several hundred years ago, humans were nearly...",
|
||||||
|
}]
|
||||||
|
}
|
||||||
mock_details.return_value = mock_tmdb_data
|
mock_details.return_value = mock_tmdb_data
|
||||||
mock_ratings.return_value = mock_content_ratings_de
|
mock_ratings.return_value = mock_content_ratings_de
|
||||||
|
|
||||||
@@ -463,7 +470,14 @@ class TestCreateTVShowNFO:
|
|||||||
patch.object(nfo_service.tmdb_client, 'get_tv_show_content_ratings', new_callable=AsyncMock) as mock_ratings, \
|
patch.object(nfo_service.tmdb_client, 'get_tv_show_content_ratings', new_callable=AsyncMock) as mock_ratings, \
|
||||||
patch.object(nfo_service, '_download_media_files', new_callable=AsyncMock):
|
patch.object(nfo_service, '_download_media_files', new_callable=AsyncMock):
|
||||||
|
|
||||||
mock_search.return_value = {"results": [{"id": 1429, "name": "Attack on Titan", "first_air_date": "2013-04-07"}]}
|
mock_search.return_value = {
|
||||||
|
"results": [{
|
||||||
|
"id": 1429,
|
||||||
|
"name": "Attack on Titan",
|
||||||
|
"first_air_date": "2013-04-07",
|
||||||
|
"overview": "Several hundred years ago, humans were nearly...",
|
||||||
|
}]
|
||||||
|
}
|
||||||
mock_details.return_value = mock_tmdb_data
|
mock_details.return_value = mock_tmdb_data
|
||||||
mock_ratings.return_value = mock_content_ratings_no_de
|
mock_ratings.return_value = mock_content_ratings_no_de
|
||||||
|
|
||||||
@@ -749,7 +763,14 @@ class TestNFOServiceEdgeCases:
|
|||||||
"poster_path": None, "backdrop_path": None
|
"poster_path": None, "backdrop_path": None
|
||||||
}
|
}
|
||||||
|
|
||||||
mock_search.return_value = {"results": [{"id": 1, "name": "Series", "first_air_date": "2020-01-01"}]}
|
mock_search.return_value = {
|
||||||
|
"results": [{
|
||||||
|
"id": 1,
|
||||||
|
"name": "Series",
|
||||||
|
"first_air_date": "2020-01-01",
|
||||||
|
"overview": "Test overview.",
|
||||||
|
}]
|
||||||
|
}
|
||||||
mock_details.return_value = tmdb_data
|
mock_details.return_value = tmdb_data
|
||||||
mock_ratings.return_value = {"results": []}
|
mock_ratings.return_value = {"results": []}
|
||||||
|
|
||||||
@@ -1486,6 +1507,67 @@ class TestEnrichFallbackLanguages:
|
|||||||
content = nfo_path.read_text(encoding="utf-8")
|
content = nfo_path.read_text(encoding="utf-8")
|
||||||
assert "<plot>Search result overview text.</plot>" in content
|
assert "<plot>Search result overview text.</plot>" in content
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_en_us_search_fallback_when_german_search_overview_empty(
|
||||||
|
self, nfo_service, tmp_path
|
||||||
|
):
|
||||||
|
"""When the German search overview is empty, fallback to en-US search overview."""
|
||||||
|
series_folder = tmp_path / "Rare Anime"
|
||||||
|
series_folder.mkdir()
|
||||||
|
|
||||||
|
empty_data = {
|
||||||
|
"id": 77777, "name": "Rare Anime",
|
||||||
|
"original_name": "新しいアニメ", "first_air_date": "2025-01-01",
|
||||||
|
"overview": "",
|
||||||
|
"vote_average": 0, "vote_count": 0,
|
||||||
|
"status": "Continuing", "episode_run_time": [],
|
||||||
|
"genres": [], "networks": [], "production_countries": [],
|
||||||
|
"poster_path": None, "backdrop_path": None,
|
||||||
|
"external_ids": {}, "credits": {"cast": []},
|
||||||
|
"images": {"logos": []},
|
||||||
|
}
|
||||||
|
|
||||||
|
async def search_side_effect(query, language="de-DE", page=1):
|
||||||
|
if language == "en-US":
|
||||||
|
return {
|
||||||
|
"results": [{
|
||||||
|
"id": 77777,
|
||||||
|
"name": "Rare Anime",
|
||||||
|
"first_air_date": "2025-01-01",
|
||||||
|
"overview": "English search overview text.",
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
"results": [{
|
||||||
|
"id": 77777,
|
||||||
|
"name": "Rare Anime",
|
||||||
|
"first_air_date": "2025-01-01",
|
||||||
|
"overview": "",
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
|
||||||
|
async def details_side_effect(tv_id, **kwargs):
|
||||||
|
return empty_data
|
||||||
|
|
||||||
|
with patch.object(nfo_service.tmdb_client, 'search_tv_show', new_callable=AsyncMock) as mock_search, \
|
||||||
|
patch.object(nfo_service.tmdb_client, 'get_tv_show_details', new_callable=AsyncMock) as mock_details, \
|
||||||
|
patch.object(nfo_service.tmdb_client, 'get_tv_show_content_ratings', new_callable=AsyncMock) as mock_ratings, \
|
||||||
|
patch.object(nfo_service, '_download_media_files', new_callable=AsyncMock):
|
||||||
|
|
||||||
|
mock_search.side_effect = search_side_effect
|
||||||
|
mock_details.side_effect = details_side_effect
|
||||||
|
mock_ratings.return_value = {"results": []}
|
||||||
|
|
||||||
|
nfo_path = await nfo_service.create_tvshow_nfo(
|
||||||
|
"Rare Anime", "Rare Anime",
|
||||||
|
download_poster=False, download_logo=False, download_fanart=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
content = nfo_path.read_text(encoding="utf-8")
|
||||||
|
assert "<plot>English search overview text.</plot>" in content
|
||||||
|
assert mock_search.call_count == 2
|
||||||
|
assert mock_search.call_args_list[1].kwargs['language'] == 'en-US'
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_no_japanese_fallback_when_english_succeeds(
|
async def test_no_japanese_fallback_when_english_succeeds(
|
||||||
self, nfo_service, tmp_path,
|
self, nfo_service, tmp_path,
|
||||||
|
|||||||
Reference in New Issue
Block a user