From bfbae88ade9aeeb5fb3e53357694f77dfac0fe17 Mon Sep 17 00:00:00 2001 From: Lukas Date: Mon, 19 Jan 2026 20:45:05 +0100 Subject: [PATCH] Skip NFO creation if exists and update DB --- .../services/background_loader_service.py | 35 ++++- tests/unit/test_background_loader_service.py | 120 ++++++++++++++++++ 2 files changed, 153 insertions(+), 2 deletions(-) diff --git a/src/server/services/background_loader_service.py b/src/server/services/background_loader_service.py index a11ca54..41da9a8 100644 --- a/src/server/services/background_loader_service.py +++ b/src/server/services/background_loader_service.py @@ -381,7 +381,7 @@ class BackgroundLoaderService: db: Database session """ task.status = LoadingStatus.LOADING_NFO - await self._broadcast_status(task, "Generating NFO file...") + await self._broadcast_status(task, "Checking NFO file...") try: # Check if NFOService is available @@ -394,6 +394,37 @@ class BackgroundLoaderService: task.progress["images"] = False return + # Check if NFO already exists + if self.series_app.nfo_service.has_nfo(task.folder): + logger.info(f"NFO already exists for {task.key}, skipping creation") + + # Update task progress + task.progress["nfo"] = True + task.progress["logo"] = True # Assume logo exists if NFO exists + task.progress["images"] = True # Assume images exist if NFO exists + + # Update database with existing NFO info + from src.server.database.service import AnimeSeriesService + series_db = await AnimeSeriesService.get_by_key(db, task.key) + if series_db: + # Only update if not already marked + if not series_db.has_nfo: + series_db.has_nfo = True + series_db.nfo_created_at = datetime.now(timezone.utc) + logger.info(f"Updated database with existing NFO for {task.key}") + if not series_db.logo_loaded: + series_db.logo_loaded = True + if not series_db.images_loaded: + series_db.images_loaded = True + await db.commit() + + logger.info(f"Existing NFO found and database updated for series: {task.key}") + return + + # NFO doesn't exist, create it + await self._broadcast_status(task, "Generating NFO file...") + logger.info(f"Creating new NFO for {task.key}") + # Use existing NFOService to create NFO with all images # This reuses all existing TMDB API logic and image downloading nfo_path = await self.series_app.nfo_service.create_tvshow_nfo( @@ -421,7 +452,7 @@ class BackgroundLoaderService: series_db.loading_status = "loading_nfo" await db.commit() - logger.info(f"NFO and images loaded for series: {task.key}") + logger.info(f"NFO and images created and loaded for series: {task.key}") except Exception as e: logger.exception(f"Failed to load NFO/images for {task.key}: {e}") diff --git a/tests/unit/test_background_loader_service.py b/tests/unit/test_background_loader_service.py index 1a5bf59..e1e1291 100644 --- a/tests/unit/test_background_loader_service.py +++ b/tests/unit/test_background_loader_service.py @@ -97,6 +97,126 @@ class TestBackgroundLoaderService: async def test_duplicate_task_handling(self, background_loader): """Test that duplicate tasks for same series are handled correctly.""" key = "test-series" + + @pytest.mark.asyncio + async def test_load_nfo_skips_if_exists(self, background_loader, mock_series_app): + """Test that NFO creation is skipped if NFO already exists.""" + # Mock has_nfo to return True (NFO exists) + mock_series_app.nfo_service.has_nfo.return_value = True + + task = SeriesLoadingTask( + key="test-series", + folder="Test Series", + name="Test Series", + year=2023 + ) + + # Mock database + mock_db = AsyncMock() + mock_series_db = Mock() + mock_series_db.has_nfo = False + mock_series_db.logo_loaded = False + mock_series_db.images_loaded = False + + with patch('src.server.database.service.AnimeSeriesService.get_by_key') as mock_get: + mock_get.return_value = mock_series_db + + # Execute + await background_loader._load_nfo_and_images(task, mock_db) + + # Verify NFO creation was NOT called + mock_series_app.nfo_service.create_tvshow_nfo.assert_not_called() + + # Verify progress was updated + assert task.progress["nfo"] is True + assert task.progress["logo"] is True + assert task.progress["images"] is True + + # Verify database was updated + assert mock_series_db.has_nfo is True + assert mock_series_db.logo_loaded is True + assert mock_series_db.images_loaded is True + mock_db.commit.assert_called_once() + + @pytest.mark.asyncio + async def test_load_nfo_creates_if_not_exists(self, background_loader, mock_series_app): + """Test that NFO is created if it doesn't exist.""" + # Mock has_nfo to return False (NFO doesn't exist) + mock_series_app.nfo_service.has_nfo.return_value = False + mock_series_app.nfo_service.create_tvshow_nfo.return_value = "/test/anime/Test Series/tvshow.nfo" + + task = SeriesLoadingTask( + key="test-series", + folder="Test Series", + name="Test Series", + year=2023 + ) + + # Mock database + mock_db = AsyncMock() + mock_series_db = Mock() + mock_series_db.has_nfo = False + + with patch('src.server.database.service.AnimeSeriesService.get_by_key') as mock_get: + mock_get.return_value = mock_series_db + + # Execute + await background_loader._load_nfo_and_images(task, mock_db) + + # Verify NFO creation WAS called + mock_series_app.nfo_service.create_tvshow_nfo.assert_called_once_with( + serie_name="Test Series", + serie_folder="Test Series", + year=2023, + download_poster=True, + download_logo=True, + download_fanart=True + ) + + # Verify progress was updated + assert task.progress["nfo"] is True + assert task.progress["logo"] is True + assert task.progress["images"] is True + + # Verify database was updated + assert mock_series_db.has_nfo is True + mock_db.commit.assert_called_once() + + @pytest.mark.asyncio + async def test_load_nfo_doesnt_update_if_already_marked(self, background_loader, mock_series_app): + """Test that database is not updated if NFO is already marked in DB.""" + # Mock has_nfo to return True (NFO exists) + mock_series_app.nfo_service.has_nfo.return_value = True + + task = SeriesLoadingTask( + key="test-series", + folder="Test Series", + name="Test Series" + ) + + # Mock database - NFO already marked + mock_db = AsyncMock() + mock_series_db = Mock() + mock_series_db.has_nfo = True # Already marked + mock_series_db.logo_loaded = True + mock_series_db.images_loaded = True + + with patch('src.server.database.service.AnimeSeriesService.get_by_key') as mock_get: + mock_get.return_value = mock_series_db + + # Execute + await background_loader._load_nfo_and_images(task, mock_db) + + # Verify database commit was still called + mock_db.commit.assert_called_once() + + # Verify NFO creation was NOT called + mock_series_app.nfo_service.create_tvshow_nfo.assert_not_called() + + @pytest.mark.asyncio + async def test_duplicate_task_handling_continued(self, background_loader): + """Test that duplicate tasks for same series are handled correctly.""" + key = "test-series" await background_loader.add_series_loading_task( key=key,