refactor: move sync_series_from_data_files to anime_service

- Moved _sync_series_to_database from fastapi_app.py to anime_service.py
- Renamed to sync_series_from_data_files for better clarity
- Updated all imports and test references
- Removed completed TODO tasks from instructions.md
This commit is contained in:
2025-12-13 09:58:32 +01:00
parent 684337fd0c
commit 5f6ac8e507
4 changed files with 106 additions and 243 deletions

View File

@@ -34,6 +34,7 @@ from src.server.controllers.page_controller import router as page_router
from src.server.middleware.auth import AuthMiddleware
from src.server.middleware.error_handler import register_exception_handlers
from src.server.middleware.setup_redirect import SetupRedirectMiddleware
from src.server.services.anime_service import sync_series_from_data_files
from src.server.services.progress_service import get_progress_service
from src.server.services.websocket_service import get_websocket_service
@@ -41,78 +42,6 @@ from src.server.services.websocket_service import get_websocket_service
# module-level globals. This makes testing and multi-instance hosting safer.
async def _sync_series_to_database(
anime_directory: str,
logger
) -> int:
"""
Sync series from data files to the database.
Scans the anime directory for data files and adds any new series
to the database. Existing series are skipped (no duplicates).
Args:
anime_directory: Path to the anime directory with data files
logger: Logger instance for logging operations
Returns:
Number of new series added to the database
"""
try:
import asyncio
from src.core.entities.SerieList import SerieList
from src.core.SeriesApp import SeriesApp
from src.server.database.connection import get_db_session
# Get all series from data files using SeriesApp
series_app = SeriesApp(anime_directory)
all_series = await asyncio.to_thread(
series_app.get_all_series_from_data_files
)
if not all_series:
logger.info("No series found in data files to sync")
return 0
logger.info(
"Found %d series in data files, syncing to database...",
len(all_series)
)
async with get_db_session() as db:
serie_list = SerieList(
anime_directory,
db_session=db,
skip_load=True
)
added_count = 0
for serie in all_series:
result = await serie_list.add_to_db(serie, db)
if result:
added_count += 1
logger.debug(
"Added series to database: %s (key=%s)",
serie.name,
serie.key
)
# Commit happens automatically via get_db_session context
logger.info(
"Synced %d new series to database (skipped %d existing)",
added_count,
len(all_series) - added_count
)
return added_count
except Exception as e:
logger.warning(
"Failed to sync series to database: %s",
e,
exc_info=True
)
return 0
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Manage application lifespan (startup and shutdown)."""
@@ -138,6 +67,10 @@ async def lifespan(app: FastAPI):
config_service = get_config_service()
config = config_service.load_config()
logger.debug(
"Config loaded: other=%s", config.other
)
# Sync anime_directory from config.json to settings
if config.other and config.other.get("anime_directory"):
settings.anime_directory = str(config.other["anime_directory"])
@@ -145,6 +78,10 @@ async def lifespan(app: FastAPI):
"Loaded anime_directory from config: %s",
settings.anime_directory
)
else:
logger.debug(
"anime_directory not found in config.other"
)
except Exception as e:
logger.warning("Failed to load config from config.json: %s", e)
@@ -172,15 +109,23 @@ async def lifespan(app: FastAPI):
try:
from src.server.utils.dependencies import get_download_service
logger.info(
"Checking anime_directory setting: '%s'",
settings.anime_directory
)
if settings.anime_directory:
download_service = get_download_service()
await download_service.initialize()
logger.info("Download service initialized and queue restored")
# Sync series from data files to database
await _sync_series_to_database(
sync_count = await sync_series_from_data_files(
settings.anime_directory, logger
)
logger.info(
"Data file sync complete. Added %d series.", sync_count
)
else:
logger.info(
"Download service initialization skipped - "

View File

@@ -361,3 +361,84 @@ class AnimeService:
def get_anime_service(series_app: SeriesApp) -> AnimeService:
"""Factory used for creating AnimeService with a SeriesApp instance."""
return AnimeService(series_app)
async def sync_series_from_data_files(
anime_directory: str,
logger=None
) -> int:
"""
Sync series from data files to the database.
Scans the anime directory for data files and adds any new series
to the database. Existing series are skipped (no duplicates).
This function is typically called during application startup to ensure
series metadata stored in filesystem data files is available in the
database.
Args:
anime_directory: Path to the anime directory with data files
logger: Optional logger instance for logging operations.
If not provided, uses structlog.
Returns:
Number of new series added to the database
"""
log = logger or structlog.get_logger(__name__)
try:
from src.core.entities.SerieList import SerieList
from src.server.database.connection import get_db_session
log.info(
"Starting data file to database sync",
directory=anime_directory
)
# Get all series from data files using SeriesApp
series_app = SeriesApp(anime_directory)
all_series = await asyncio.to_thread(
series_app.get_all_series_from_data_files
)
if not all_series:
log.info("No series found in data files to sync")
return 0
log.info(
"Found series in data files, syncing to database",
count=len(all_series)
)
async with get_db_session() as db:
serie_list = SerieList(
anime_directory,
db_session=db,
skip_load=True
)
added_count = 0
for serie in all_series:
result = await serie_list.add_to_db(serie, db)
if result:
added_count += 1
log.debug(
"Added series to database",
name=serie.name,
key=serie.key
)
log.info(
"Data file sync complete",
added=added_count,
skipped=len(all_series) - added_count
)
return added_count
except Exception as e:
log.warning(
"Failed to sync series to database",
error=str(e),
exc_info=True
)
return 0