feat: add ImageLoadingService for downloading series artwork

- Create ImageLoadingService that downloads poster.jpg, fanart.jpg, and
  logo.png from TMDB when anime is added or during scheduler rescan
- Integrate into BackgroundLoaderService._load_nfo_and_images() to trigger
  image downloads when new anime is added
- Add image_scan_after_rescan config option to scheduler (default: true)
- Add _run_image_scan() to scheduler rescan flow, processing series in
  batches of 10 to respect TMDB rate limits
- Fix SearchResult model missing folder, snippet, and score fields
- Update background_loader tests to match new image loading behavior
This commit is contained in:
2026-06-14 20:51:57 +02:00
parent 6dc3cda810
commit 7a1b2e565e
6 changed files with 617 additions and 70 deletions

View File

@@ -497,24 +497,55 @@ class BackgroundLoaderService:
async def _load_nfo_and_images(self, task: SeriesLoadingTask, db: Any) -> bool:
"""Load NFO file and images for a series.
Note: NFO service has been removed. This method now just marks
progress as False since NFO handling moved to server layer.
Downloads poster.jpg, fanart.jpg, and logo.png from TMDB
using the ImageLoadingService.
Args:
task: The loading task
db: Database session
Returns:
bool: Always False since NFO service removed
bool: True if any images were loaded, False otherwise
"""
task.status = LoadingStatus.LOADING_NFO
await self._broadcast_status(task, "NFO loading disabled...")
task.progress["nfo"] = False
task.progress["logo"] = False
task.progress["images"] = False
return False
await self._broadcast_status(task, "Loading images...")
try:
from src.server.nfo.tmdb_client import get_tmdb_client
from src.server.services.image_loading_service import (
init_image_loading_service,
)
tmdb_client = get_tmdb_client()
image_service = init_image_loading_service(tmdb_client)
result = await image_service.load_series_images(
key=task.key,
folder=task.folder,
anime_directory=self.series_app.directory_to_search,
db=db,
)
task.progress["nfo"] = True # NFO was already created earlier in the flow
task.progress["logo"] = result.get("logo", False)
task.progress["images"] = result.get("poster", False) and result.get("fanart", False)
logger.info(
"Images loaded for series %s: poster=%s fanart=%s logo=%s",
task.key,
result.get("poster", False),
result.get("fanart", False),
result.get("logo", False),
)
return True
except Exception as e:
logger.warning("Failed to load images for series %s: %s", task.key, e)
task.progress["nfo"] = True
task.progress["logo"] = False
task.progress["images"] = False
return False
async def _scan_missing_episodes(self, task: SeriesLoadingTask, db: Any) -> None:
"""Scan for missing episodes after NFO creation.