fix: prevent folder scan during NFO processing on startup

- Modified SeriesManagerService to create SerieList with skip_load=True
- Changed scan_and_process_nfo() to load series from database instead of filesystem
- Fixed database transaction issue by creating separate session per task
- Verified scans only run once during initial setup, not on normal startup
This commit is contained in:
2026-01-21 20:07:19 +01:00
parent 88c00b761c
commit 61c86dc698
2 changed files with 87 additions and 88 deletions

View File

@@ -58,7 +58,8 @@ class SeriesManagerService:
image_size: Image size to download image_size: Image size to download
""" """
self.anime_directory = anime_directory self.anime_directory = anime_directory
self.serie_list = SerieList(anime_directory) # Skip automatic folder scanning - we load from database instead
self.serie_list = SerieList(anime_directory, skip_load=True)
# NFO configuration # NFO configuration
self.auto_create_nfo = auto_create_nfo self.auto_create_nfo = auto_create_nfo
@@ -107,8 +108,7 @@ class SeriesManagerService:
serie_folder: str, serie_folder: str,
serie_name: str, serie_name: str,
serie_key: str, serie_key: str,
year: Optional[int] = None, year: Optional[int] = None
db=None
): ):
"""Process NFO file for a series (create or update). """Process NFO file for a series (create or update).
@@ -117,7 +117,6 @@ class SeriesManagerService:
serie_name: Series display name serie_name: Series display name
serie_key: Series unique identifier for database updates serie_key: Series unique identifier for database updates
year: Release year (helps with TMDB matching) year: Release year (helps with TMDB matching)
db: Optional database session for updating IDs
""" """
if not self.nfo_service: if not self.nfo_service:
return return
@@ -128,20 +127,24 @@ class SeriesManagerService:
nfo_exists = await self.nfo_service.check_nfo_exists(serie_folder) nfo_exists = await self.nfo_service.check_nfo_exists(serie_folder)
# If NFO exists, parse IDs and update database # If NFO exists, parse IDs and update database
if nfo_exists and db: if nfo_exists:
logger.debug(f"Parsing IDs from existing NFO for '{serie_name}'") logger.debug(f"Parsing IDs from existing NFO for '{serie_name}'")
ids = self.nfo_service.parse_nfo_ids(nfo_path) ids = self.nfo_service.parse_nfo_ids(nfo_path)
if ids["tmdb_id"] or ids["tvdb_id"]: if ids["tmdb_id"] or ids["tvdb_id"]:
# Update database with extracted IDs # Create database session for this task
from datetime import datetime, timezone from datetime import datetime, timezone
from sqlalchemy import select from sqlalchemy import select
from src.server.database.connection import get_db_session
from src.server.database.models import AnimeSeries from src.server.database.models import AnimeSeries
async with get_db_session() as db:
result = await db.execute( result = await db.execute(
select(AnimeSeries).filter(AnimeSeries.key == serie_key) select(AnimeSeries).filter(
AnimeSeries.key == serie_key
)
) )
series = result.scalars().first() series = result.scalars().first()
@@ -175,8 +178,8 @@ class SeriesManagerService:
) )
else: else:
logger.warning( logger.warning(
f"Series not found in database for NFO ID update: " f"Series not found in database for NFO ID "
f"{serie_key}" f"update: {serie_key}"
) )
# Create or update NFO file if configured # Create or update NFO file if configured
@@ -218,8 +221,9 @@ class SeriesManagerService:
"""Scan all series and process NFO files based on configuration. """Scan all series and process NFO files based on configuration.
This method: This method:
1. Uses SerieList to scan series folders 1. Loads series from database (avoiding filesystem scan)
2. For each series with existing NFO, reads TMDB/TVDB IDs and updates database 2. For each series with existing NFO, reads TMDB/TVDB IDs
and updates database
3. For each series without NFO (if auto_create=True), creates one 3. For each series without NFO (if auto_create=True), creates one
4. For each series with NFO (if update_on_scan=True), updates it 4. For each series with NFO (if update_on_scan=True), updates it
5. Runs operations concurrently for better performance 5. Runs operations concurrently for better performance
@@ -228,34 +232,34 @@ class SeriesManagerService:
logger.info("NFO service not enabled, skipping NFO processing") logger.info("NFO service not enabled, skipping NFO processing")
return return
# Get all series from SerieList # Import database dependencies
all_series = self.serie_list.get_all() from src.server.database.connection import get_db_session
from src.server.database.service import AnimeSeriesService
if not all_series: # Load series from database (not from filesystem)
logger.info("No series found to process") async with get_db_session() as db:
anime_series_list = await AnimeSeriesService.get_all(
db, with_episodes=False
)
if not anime_series_list:
logger.info("No series found in database to process")
return return
logger.info(f"Processing NFO for {len(all_series)} series...") logger.info(f"Processing NFO for {len(anime_series_list)} series...")
# Import database session
from src.server.database.connection import get_db_session
# Create database session for ID updates
async with get_db_session() as db:
# Create tasks for concurrent processing # Create tasks for concurrent processing
# Each task creates its own database session
tasks = [] tasks = []
for serie in all_series: for anime_series in anime_series_list:
# Extract year from first air date if available # Extract year if available
year = None year = getattr(anime_series, 'year', None)
if hasattr(serie, 'year') and serie.year:
year = serie.year
task = self.process_nfo_for_series( task = self.process_nfo_for_series(
serie_folder=serie.folder, serie_folder=anime_series.folder,
serie_name=serie.name, serie_name=anime_series.name,
serie_key=serie.key, serie_key=anime_series.key,
year=year, year=year
db=db
) )
tasks.append(task) tasks.append(task)
@@ -269,11 +273,6 @@ class SeriesManagerService:
if i + batch_size < len(tasks): if i + batch_size < len(tasks):
await asyncio.sleep(2) await asyncio.sleep(2)
logger.info("NFO processing complete")
def get_serie_list(self) -> SerieList:
"""Get the underlying SerieList instance.
Returns: Returns:
SerieList instance SerieList instance
""" """