fix: ensure all NFO properties are written on creation

- Add showtitle and namedseason to mapper output
- Add multi-language fallback (en-US, ja-JP) for empty overview
- Use search result overview as last resort fallback
- Add tests for new NFO creation behavior
This commit is contained in:
2026-03-06 21:20:17 +01:00
parent b34ee59bca
commit 69b409f42d
4 changed files with 294 additions and 32 deletions

View File

@@ -160,7 +160,7 @@ class NFOService:
logger.info(f"Found match: {tv_show['name']} (ID: {tv_id})")
# Get detailed information
# Get detailed information with multi-language image support
details = await self.tmdb_client.get_tv_show_details(
tv_id,
append_to_response="credits,external_ids,images"
@@ -169,8 +169,12 @@ class NFOService:
# Get content ratings for FSK
content_ratings = await self.tmdb_client.get_tv_show_content_ratings(tv_id)
# Enrich with English fallback for empty overview/tagline
details = await self._enrich_details_with_fallback(details)
# Enrich with fallback languages for empty overview/tagline
# Pass search result overview as last resort fallback
search_overview = tv_show.get("overview") or None
details = await self._enrich_details_with_fallback(
details, search_overview=search_overview
)
# Convert TMDB data to TVShowNFO model
nfo_model = tmdb_to_nfo_model(
@@ -267,9 +271,8 @@ class NFOService:
# Get content ratings for FSK
content_ratings = await self.tmdb_client.get_tv_show_content_ratings(tmdb_id)
# Enrich with English fallback for empty overview/tagline
details = await self._enrich_details_with_fallback(details)
# Enrich with fallback languages for empty overview/tagline
details = await self._enrich_details_with_fallback(details)
# Convert TMDB data to TVShowNFO model
nfo_model = tmdb_to_nfo_model(
details,
@@ -381,20 +384,26 @@ class NFOService:
async def _enrich_details_with_fallback(
self,
details: Dict[str, Any],
search_overview: Optional[str] = None,
) -> Dict[str, Any]:
"""Enrich TMDB details with English fallback for empty fields.
"""Enrich TMDB details with fallback languages for empty fields.
When requesting details in ``de-DE``, some anime have an empty
``overview`` (and potentially other translatable fields). This
method detects empty values and fills them from the English
(``en-US``) endpoint so that NFO files always contain a ``plot``
regardless of whether the German translation exists.
method detects empty values and fills them from alternative
languages (``en-US``, then ``ja-JP``) so that NFO files always
contain a ``plot`` regardless of whether the German translation
exists. As a last resort, the overview from the search result
is used.
Args:
details: TMDB TV show details (language ``de-DE``).
search_overview: Overview text from the TMDB search result,
used as a final fallback if all language-specific
requests fail or return empty overviews.
Returns:
The *same* dict, mutated in-place with English fallbacks
The *same* dict, mutated in-place with fallback values
where needed.
"""
overview = details.get("overview") or ""
@@ -403,32 +412,46 @@ class NFOService:
# Overview already populated nothing to do.
return details
logger.debug(
"German overview empty for TMDB ID %s, fetching English fallback",
details.get("id"),
)
tmdb_id = details.get("id")
fallback_languages = ["en-US", "ja-JP"]
try:
en_details = await self.tmdb_client.get_tv_show_details(
details["id"],
language="en-US",
for lang in fallback_languages:
if details.get("overview"):
break
logger.debug(
"Trying %s fallback for TMDB ID %s",
lang, tmdb_id,
)
if en_details.get("overview"):
details["overview"] = en_details["overview"]
logger.info(
"Used English overview fallback for TMDB ID %s",
details.get("id"),
try:
lang_details = await self.tmdb_client.get_tv_show_details(
tmdb_id,
language=lang,
)
# Also fill tagline if missing
if not details.get("tagline") and en_details.get("tagline"):
details["tagline"] = en_details["tagline"]
except Exception as exc: # pylint: disable=broad-except
logger.warning(
"Failed to fetch English fallback for TMDB ID %s: %s",
details.get("id"),
exc,
if not details.get("overview") and lang_details.get("overview"):
details["overview"] = lang_details["overview"]
logger.info(
"Used %s overview fallback for TMDB ID %s",
lang, tmdb_id,
)
# Also fill tagline if missing
if not details.get("tagline") and lang_details.get("tagline"):
details["tagline"] = lang_details["tagline"]
except Exception as exc: # pylint: disable=broad-except
logger.warning(
"Failed to fetch %s fallback for TMDB ID %s: %s",
lang, tmdb_id, exc,
)
# Last resort: use search result overview
if not details.get("overview") and search_overview:
details["overview"] = search_overview
logger.info(
"Used search result overview fallback for TMDB ID %s",
tmdb_id,
)
return details