diff --git a/api/routes.py b/api/routes.py index 602432b..676f3ec 100644 --- a/api/routes.py +++ b/api/routes.py @@ -806,7 +806,8 @@ async def manual_scan(background_tasks: BackgroundTasks, path: Optional[str] = N series_path = scan_path.parent tv_processor_obj = dependencies.get("tv_processor") sonarr_client = tv_processor_obj.sonarr if tv_processor_obj and hasattr(tv_processor_obj, 'sonarr') else None - if nfo_manager.parse_imdb_from_path_with_nfo_fallback(series_path, sonarr_client): + shutdown_event = dependencies.get("shutdown_event") + if nfo_manager.parse_imdb_from_path_with_nfo_fallback(series_path, sonarr_client, shutdown_event): print(f"INFO: Processing single season: {scan_path}") try: tv_processor.process_season(series_path, scan_path) @@ -818,7 +819,8 @@ async def manual_scan(background_tasks: BackgroundTasks, path: Optional[str] = N series_path = season_path.parent tv_processor_obj = dependencies.get("tv_processor") sonarr_client = tv_processor_obj.sonarr if tv_processor_obj and hasattr(tv_processor_obj, 'sonarr') else None - if nfo_manager.parse_imdb_from_path_with_nfo_fallback(series_path, sonarr_client): + shutdown_event = dependencies.get("shutdown_event") + if nfo_manager.parse_imdb_from_path_with_nfo_fallback(series_path, sonarr_client, shutdown_event): print(f"INFO: Processing single episode: {scan_path}") try: tv_processor.process_episode_file(series_path, season_path, scan_path) @@ -828,7 +830,8 @@ async def manual_scan(background_tasks: BackgroundTasks, path: Optional[str] = N # Check if this path itself is a series (has IMDb ID in directory name or NFO files) tv_processor_obj = dependencies.get("tv_processor") sonarr_client = tv_processor_obj.sonarr if tv_processor_obj and hasattr(tv_processor_obj, 'sonarr') else None - if nfo_manager.parse_imdb_from_path_with_nfo_fallback(scan_path, sonarr_client): + shutdown_event = dependencies.get("shutdown_event") + if nfo_manager.parse_imdb_from_path_with_nfo_fallback(scan_path, sonarr_client, shutdown_event): try: # Determine force_scan based on scan mode force_scan = (scan_mode == "full") @@ -848,6 +851,12 @@ async def manual_scan(background_tasks: BackgroundTasks, path: Optional[str] = N # Count total series first for progress tracking tv_series_list = [] for item in scan_path.iterdir(): + # Check for shutdown signal during series discovery + shutdown_event = dependencies.get("shutdown_event") + if shutdown_event and shutdown_event.is_set(): + print("INFO: ⚠️ SHUTDOWN SIGNAL RECEIVED - Stopping series discovery") + return + if (item.is_dir() and not item.name.lower().startswith('season') and not re.match(r'^season\s+\d+$', item.name, re.IGNORECASE)): @@ -855,12 +864,13 @@ async def manual_scan(background_tasks: BackgroundTasks, path: Optional[str] = N # Check for IMDb ID (enhanced with NFO fallback) tv_processor_obj = dependencies.get("tv_processor") sonarr_client = tv_processor_obj.sonarr if tv_processor_obj and hasattr(tv_processor_obj, 'sonarr') else None - imdb_id = nfo_manager.parse_imdb_from_path_with_nfo_fallback(item, sonarr_client) + imdb_id = nfo_manager.parse_imdb_from_path_with_nfo_fallback(item, sonarr_client, shutdown_event) if imdb_id: tv_series_list.append(item) else: # Log missing IMDb ID for TV series try: + db = dependencies.get("db") db.add_missing_imdb( file_path=str(item), media_type="tv", @@ -918,6 +928,12 @@ async def manual_scan(background_tasks: BackgroundTasks, path: Optional[str] = N # Count total movies first for progress tracking movie_list = [] for item in scan_path.iterdir(): + # Check for shutdown signal during movie discovery + shutdown_event = dependencies.get("shutdown_event") + if shutdown_event and shutdown_event.is_set(): + print("INFO: ⚠️ SHUTDOWN SIGNAL RECEIVED - Stopping movie discovery") + return + if item.is_dir(): # Check for IMDb ID imdb_id = nfo_manager.find_movie_imdb_id(item) @@ -926,6 +942,7 @@ async def manual_scan(background_tasks: BackgroundTasks, path: Optional[str] = N else: # Log missing IMDb ID for movie try: + db = dependencies.get("db") db.add_missing_imdb( file_path=str(item), media_type="movie", diff --git a/core/nfo_manager.py b/core/nfo_manager.py index 972582a..9010b0c 100644 --- a/core/nfo_manager.py +++ b/core/nfo_manager.py @@ -50,7 +50,7 @@ class NFOManager: return None - def parse_imdb_from_path_with_nfo_fallback(self, path: Path, sonarr_client=None) -> Optional[str]: + def parse_imdb_from_path_with_nfo_fallback(self, path: Path, sonarr_client=None, shutdown_event=None) -> Optional[str]: """ Enhanced IMDb detection that fallback to Sonarr ID lookup from NFO files @@ -63,6 +63,10 @@ class NFOManager: if imdb_id: return imdb_id + # Check for shutdown signal before expensive operations + if shutdown_event and shutdown_event.is_set(): + return None + # Fallback: Check NFO files for Sonarr series ID if not sonarr_client or not sonarr_client.enabled: return None @@ -79,6 +83,10 @@ class NFOManager: # Extract Sonarr series ID from any NFO file for nfo_file in nfo_files: + # Check for shutdown signal during NFO processing + if shutdown_event and shutdown_event.is_set(): + return None + try: tree = ET.parse(nfo_file) root = tree.getroot() @@ -87,6 +95,10 @@ class NFOManager: for uniqueid in root.findall('.//uniqueid[@type="sonarr"]'): sonarr_id = uniqueid.text if sonarr_id and sonarr_id.isdigit(): + # Check for shutdown signal before API call + if shutdown_event and shutdown_event.is_set(): + return None + # Look up series in Sonarr to get IMDb ID series_data = sonarr_client.get_series_by_id(int(sonarr_id)) if series_data: diff --git a/docker-compose.example.yml b/docker-compose.example.yml index 71258f1..0a32f0f 100644 --- a/docker-compose.example.yml +++ b/docker-compose.example.yml @@ -122,4 +122,23 @@ networks: # - Web interface operations don't impact core processing # - Webhooks remain responsive during long scans # - Independent scaling and resource allocation -# - Separated concerns for maintenance and updates \ No newline at end of file +# - Separated concerns for maintenance and updates + # NFOGuard Core (Processing Engine) + nfoguard: + # ... other settings ... + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/health/simple"] + interval: 30s + timeout: 15s # Increased from 10s + retries: 3 + start_period: 60s # Increased from 40s + + # NFOGuard Web Interface + nfoguard-web: + # ... other settings ... + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8081/health"] + interval: 30s + timeout: 15s # Increased from 10s + retries: 3 + start_period: 30s # Increased from 10s \ No newline at end of file