From a3840729017aa7c32e86412f8bf7e3da73b62c39 Mon Sep 17 00:00:00 2001 From: Lukas Date: Sun, 26 Jul 2026 20:02:02 +0200 Subject: [PATCH] fix: queue background loading after folder resolve; extract year from NFO --- src/server/api/setup_endpoints.py | 23 +++++++++++++ src/server/services/nfo_scan_service.py | 45 ++++++++++++++++++------- 2 files changed, 56 insertions(+), 12 deletions(-) diff --git a/src/server/api/setup_endpoints.py b/src/server/api/setup_endpoints.py index 6c61f54..b73a0aa 100644 --- a/src/server/api/setup_endpoints.py +++ b/src/server/api/setup_endpoints.py @@ -14,7 +14,9 @@ from pydantic import BaseModel, Field from src.server.database.connection import get_db_session from src.server.database.service import AnimeSeriesService, UnresolvedFolderService +from src.server.services.background_loader_service import BackgroundLoaderService from src.server.utils.dependencies import ( + get_background_loader_service, get_database_session, get_series_app, require_auth, @@ -150,6 +152,7 @@ async def resolve_unresolved_folder( folder_name: str, request: ResolveFolderRequest, db=Depends(get_database_session), + background_loader: BackgroundLoaderService = Depends(get_background_loader_service), ) -> ResolveFolderResponse: """Resolve an unresolved folder by providing the correct provider key. @@ -215,6 +218,26 @@ async def resolve_unresolved_folder( folder_name, request.provider_key, series.id ) + # Queue background loading task for episodes, NFO, and images + try: + await background_loader.add_series_loading_task( + key=request.provider_key, + folder=folder_name, + name=unresolved.title, + year=unresolved.year, + ) + logger.info( + "Queued background loading for resolved folder: %s (key=%s)", + folder_name, + request.provider_key + ) + except Exception as e: + logger.warning( + "Failed to queue background loading for resolved folder %s: %s", + folder_name, + e + ) + return ResolveFolderResponse( status="success", message=f"Successfully resolved and added series: {unresolved.title}", diff --git a/src/server/services/nfo_scan_service.py b/src/server/services/nfo_scan_service.py index 75545ed..717a71b 100644 --- a/src/server/services/nfo_scan_service.py +++ b/src/server/services/nfo_scan_service.py @@ -350,11 +350,16 @@ class NfoScanService: return "created" # NFO exists — check if it needs updating - updated = await self._update_nfo_if_needed(key, folder, series_data, nfo_path) + updated, year = await self._update_nfo_if_needed(key, folder, series_data, nfo_path) if updated: - await self._update_series_nfo_flag(key, has_nfo=True, nfo_path=nfo_path) + await self._update_series_nfo_flag(key, has_nfo=True, nfo_path=nfo_path, year=year) return "updated" + # NFO is valid but series may still be missing year — try to extract from NFO + if year is not None and series_data.get("year") is None: + logger.info("Extracted year %d from NFO for %s — updating database", year, key) + await self._update_series_nfo_flag(key, has_nfo=True, nfo_path=nfo_path, year=year) + return None async def _create_nfo( @@ -421,7 +426,7 @@ class NfoScanService: folder: str, series_data: Dict[str, Any], nfo_path: str, - ) -> bool: + ) -> tuple[bool, Optional[int]]: """Load existing NFO, check for missing fields, fill and rewrite. Args: @@ -431,13 +436,13 @@ class NfoScanService: nfo_path: Full path to the existing NFO file Returns: - True if NFO was updated, False if no changes were needed. + Tuple of (True if NFO was updated, extracted year from NFO or None). """ try: from lxml import etree except ImportError: logger.warning("lxml not available — cannot update existing NFO files") - return False + return False, None try: tree = etree.parse(nfo_path) @@ -445,7 +450,17 @@ class NfoScanService: except Exception as exc: logger.warning("Failed to parse existing NFO for %s: %s — will regenerate", key, exc) # Corrupt or unreadable NFO — regenerate from TMDB - return await self._regenerate_nfo(key, folder, series_data, nfo_path) + updated = await self._regenerate_nfo(key, folder, series_data, nfo_path) + return updated, None + + # Extract year from NFO if present + year: Optional[int] = None + year_elem = root.find("year") + if year_elem is not None and year_elem.text and year_elem.text.strip(): + try: + year = int(year_elem.text.strip()) + except ValueError: + logger.debug("Invalid year value in NFO for %s: %s", key, year_elem.text) # Check for missing or empty critical fields critical_fields = ["title", "plot", "premiered", "tmdbid"] @@ -458,7 +473,7 @@ class NfoScanService: if not missing_fields: logger.debug("NFO for %s is complete — no update needed", key) - return False + return False, year logger.info( "NFO for %s is missing fields %s — attempting to fill from TMDB", @@ -470,16 +485,16 @@ class NfoScanService: tmdb_id = series_data.get("tmdb_id") if not tmdb_id: logger.warning("Cannot update NFO for %s: no tmdb_id", key) - return False + return False, year try: tmdb_data = await self._fetch_tmdb_data(tmdb_id) except Exception as exc: logger.warning("Failed to fetch TMDB data for %s: %s", key, exc) - return False + return False, year if not tmdb_data: - return False + return False, year nfo_model = tmdb_to_nfo_model( tmdb_data, @@ -504,7 +519,7 @@ class NfoScanService: "missing_fields": missing_fields, }) - return True + return True, year async def _regenerate_nfo( self, @@ -626,13 +641,15 @@ class NfoScanService: key: str, has_nfo: bool, nfo_path: str, + year: Optional[int] = None, ) -> None: - """Update the has_nfo flag and nfo_path in the database. + """Update the has_nfo flag, nfo_path, and optionally year in the database. Args: key: Series key (primary identifier) has_nfo: Whether the series now has an NFO file nfo_path: Path to the NFO file + year: Optional year extracted from NFO to save to DB """ try: from src.server.database.connection import get_db_session @@ -647,6 +664,10 @@ class NfoScanService: if series.nfo_created_at is None: series.nfo_created_at = now series.nfo_updated_at = now + # Update year if series has no year and we have one from NFO + if year is not None and series.year is None: + series.year = year + logger.info("Updated year to %d for series: %s", year, key) await db.flush() logger.debug("Updated NFO flag for series: %s", key) except Exception as exc: