Add sync_single_series_after_scan with NFO metadata and WebSocket updates

- Implement sync_single_series_after_scan to persist scanned series to database
- Enhanced _broadcast_series_updated to include full NFO metadata (nfo_created_at, nfo_updated_at, tmdb_id, tvdb_id)
- Add immediate episode scanning in add_series endpoint when background loader isn't running
- Implement updateSingleSeries in frontend to handle series_updated WebSocket events
- Add SERIES_UPDATED event constant to WebSocket event definitions
- Update background loader to use sync_single_series_after_scan method
- Simplified background loader initialization in FastAPI app
- Add comprehensive tests for series update WebSocket payload and episode counting logic
- Import reorganization: move get_background_loader_service to dependencies module
This commit is contained in:
2026-02-06 18:36:39 +01:00
parent d74c181556
commit d72b8cb1ab
9 changed files with 1078 additions and 21 deletions

View File

@@ -15,12 +15,10 @@ from src.server.exceptions import (
ValidationError,
)
from src.server.services.anime_service import AnimeService, AnimeServiceError
from src.server.services.background_loader_service import (
BackgroundLoaderService,
get_background_loader_service,
)
from src.server.services.background_loader_service import BackgroundLoaderService
from src.server.utils.dependencies import (
get_anime_service,
get_background_loader_service,
get_optional_database_session,
get_series_app,
require_auth,
@@ -641,6 +639,7 @@ async def add_series(
request: AddSeriesRequest,
_auth: dict = Depends(require_auth),
series_app: Any = Depends(get_series_app),
anime_service: AnimeService = Depends(get_anime_service),
db: Optional[AsyncSession] = Depends(get_optional_database_session),
background_loader: BackgroundLoaderService = Depends(get_background_loader_service),
) -> dict:
@@ -831,8 +830,44 @@ async def add_series(
key,
e
)
# Step F: Scan missing episodes immediately if background loader is not running
# Uses existing SerieScanner and AnimeService sync to avoid duplicates
try:
loader_running = (
background_loader.worker_task is not None
and not background_loader.worker_task.done()
)
if (
not loader_running
and series_app
and hasattr(series_app, "serie_scanner")
):
missing_episodes = series_app.serie_scanner.scan_single_series(
key=key,
folder=folder
)
total_missing = sum(
len(eps) for eps in missing_episodes.values()
)
logger.info(
"Scanned %d missing episodes for %s",
total_missing,
key
)
# Persist scan results to database (includes episodes)
# scan_single_series updates serie_scanner.keyDict with episodeDict
# sync_single_series_after_scan retrieves from there and saves to DB
await anime_service.sync_single_series_after_scan(key)
except Exception as e:
logger.warning(
"Failed to scan missing episodes for %s: %s",
key,
e
)
# Step F: Return immediate response (202 Accepted)
# Step G: Return immediate response (202 Accepted)
response = {
"status": "success",
"message": f"Series added successfully: {name}. Data will be loaded in background.",