diff --git a/src/core/services/nfo_service.py b/src/core/services/nfo_service.py
index 6c855fd..46d05f2 100644
--- a/src/core/services/nfo_service.py
+++ b/src/core/services/nfo_service.py
@@ -174,6 +174,32 @@ class NFOService:
# Enrich with fallback languages for empty overview/tagline
# Pass search result overview as last resort fallback
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, search_overview=search_overview
)
diff --git a/tests/unit/test_nfo_service.py b/tests/unit/test_nfo_service.py
index 20d2733..1824984 100644
--- a/tests/unit/test_nfo_service.py
+++ b/tests/unit/test_nfo_service.py
@@ -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, '_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_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, '_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_ratings.return_value = mock_content_ratings_no_de
@@ -749,7 +763,14 @@ class TestNFOServiceEdgeCases:
"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_ratings.return_value = {"results": []}
@@ -1486,6 +1507,67 @@ class TestEnrichFallbackLanguages:
content = nfo_path.read_text(encoding="utf-8")
assert "Search result overview text." 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 "English search overview text." in content
+ assert mock_search.call_count == 2
+ assert mock_search.call_args_list[1].kwargs['language'] == 'en-US'
+
@pytest.mark.asyncio
async def test_no_japanese_fallback_when_english_succeeds(
self, nfo_service, tmp_path,