From 6ad14c03b5b2307dccc40e4e9fa8b1f455e1ab7e Mon Sep 17 00:00:00 2001 From: Lukas Date: Sun, 19 Apr 2026 18:49:21 +0200 Subject: [PATCH] Task 3: remove non-reentrant TMDB context in NFOService and mark task done --- docs/tasks.md | 2 ++ src/core/services/nfo_service.py | 48 ++++++++++++++++++-------------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/docs/tasks.md b/docs/tasks.md index 2d20157..9af0525 100644 --- a/docs/tasks.md +++ b/docs/tasks.md @@ -98,6 +98,8 @@ If the TMDB API key is configured only via `config.json` (not the `TMDB_API_KEY` ## Task 3 — Remove non-reentrant `async with self.tmdb_client:` from NFOService public methods +- [x] Completed + ### Where `src/core/services/nfo_service.py` — `create_tvshow_nfo` (~line 151) and `update_tvshow_nfo` (~line 265) diff --git a/src/core/services/nfo_service.py b/src/core/services/nfo_service.py index 0431dc5..6c855fd 100644 --- a/src/core/services/nfo_service.py +++ b/src/core/services/nfo_service.py @@ -146,36 +146,38 @@ class NFOService: logger.info("Creating series folder: %s", folder_path) folder_path.mkdir(parents=True, exist_ok=True) - async with self.tmdb_client: + try: + await self.tmdb_client._ensure_session() + # Search for TV show with clean name (without year) logger.debug("Searching TMDB for: %s", search_name) search_results = await self.tmdb_client.search_tv_show(search_name) - + if not search_results.get("results"): raise TMDBAPIError(f"No results found for: {search_name}") - + # Find best match (consider year if provided) tv_show = self._find_best_match(search_results["results"], search_name, year) tv_id = tv_show["id"] - + logger.info("Found match: %s (ID: %s)", tv_show['name'], tv_id) - + # 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" ) - + # Get content ratings for FSK content_ratings = await self.tmdb_client.get_tv_show_content_ratings(tv_id) - + # 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( details, @@ -183,15 +185,15 @@ class NFOService: self.tmdb_client.get_image_url, self.image_size, ) - + # Generate XML nfo_xml = generate_tvshow_nfo(nfo_model) - + # Save NFO file nfo_path = folder_path / "tvshow.nfo" nfo_path.write_text(nfo_xml, encoding="utf-8") logger.info("Created NFO: %s", nfo_path) - + # Download media files await self._download_media_files( details, @@ -200,8 +202,10 @@ class NFOService: download_logo=download_logo, download_fanart=download_fanart ) - + return nfo_path + finally: + await self.tmdb_client.close() async def update_tvshow_nfo( self, @@ -260,19 +264,19 @@ class NFOService: except ValueError as e: raise TMDBAPIError(f"Invalid TMDB ID format in NFO: {e}") - # Fetch fresh data from TMDB - async with self.tmdb_client: + try: + await self.tmdb_client._ensure_session() logger.debug("Fetching fresh data for TMDB ID: %s", tmdb_id) details = await self.tmdb_client.get_tv_show_details( tmdb_id, append_to_response="credits,external_ids,images" ) - + # Get content ratings for FSK content_ratings = await self.tmdb_client.get_tv_show_content_ratings(tmdb_id) - + # Enrich with fallback languages for empty overview/tagline - details = await self._enrich_details_with_fallback(details) + details = await self._enrich_details_with_fallback(details) # Convert TMDB data to TVShowNFO model nfo_model = tmdb_to_nfo_model( details, @@ -280,14 +284,14 @@ class NFOService: self.tmdb_client.get_image_url, self.image_size, ) - + # Generate XML nfo_xml = generate_tvshow_nfo(nfo_model) - + # Save updated NFO file nfo_path.write_text(nfo_xml, encoding="utf-8") logger.info("Updated NFO: %s", nfo_path) - + # Re-download media files if requested if download_media: await self._download_media_files( @@ -297,8 +301,10 @@ class NFOService: download_logo=True, download_fanart=True ) - + return nfo_path + finally: + await self.tmdb_client.close() def parse_nfo_ids(self, nfo_path: Path) -> Dict[str, Optional[int]]: """Parse TMDB ID and TVDB ID from an existing NFO file.