structlog fails with BrokenPipeError when stdout is redirected (e.g., background
processes, Docker logs). Replace all structlog.get_logger() calls with
logging.getLogger() and convert keyword-style log calls to %-format strings.
Also removes stale Docs/tasks.md (2028 lines) and updates Robot Framework
tests to match current API behavior.
- 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
- 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
- Created src/server/utils/media.py with reusable media file functions
- Functions: check_media_files(), get_media_file_paths(), has_all_images(), count_video_files(), has_video_files()
- Defined standard filename constants: POSTER_FILENAME, LOGO_FILENAME, FANART_FILENAME, NFO_FILENAME
- Defined VIDEO_EXTENSIONS set for media player compatibility
- Refactored src/server/api/nfo.py (7 locations) to use utility functions
- Refactored src/server/services/background_loader_service.py to use utility
- Functions accept both str and Path for compatibility
- Marked Code Duplications 1, 3, 4 as RESOLVED in instructions.md
- Updated Further Considerations as RESOLVED (addressed in Issues 7, 9, 10)
- Modified BackgroundLoaderService to use multiple workers (default: 5)
- Anime additions now process in parallel without blocking
- Added comprehensive unit tests for concurrent behavior
- Updated integration tests for compatibility
- Updated architecture documentation
- Added _find_series_directory() to locate series without full rescan
- Added _scan_series_episodes() to scan only target series directory
- Modified _load_episodes() to use targeted scanning instead of anime_service.rescan()
- Added 15 comprehensive unit tests for optimization
- Performance improvement: <1s vs 30-60s for large libraries
- All tests passing (15 new tests + 14 existing background loader tests)
- Changed 'async for' to 'async with' for get_db_session()
- get_db_session() is @asynccontextmanager, requires async with not async for
- Created 5 comprehensive unit tests verifying the fix
- All tests pass, background loading now works correctly
- Add loading status fields to AnimeSeries model
- Create BackgroundLoaderService for async task processing
- Update POST /api/anime/add to return 202 Accepted immediately
- Add GET /api/anime/{key}/loading-status endpoint
- Integrate background loader with startup/shutdown lifecycle
- Create database migration script for loading status fields
- Add unit tests for BackgroundLoaderService (10 tests, all passing)
- Update AnimeSeriesService.create() to accept loading status fields
Architecture follows clean separation with no code duplication:
- BackgroundLoader orchestrates, doesn't reimplement
- Reuses existing AnimeService, NFOService, WebSocket patterns
- Database-backed status survives restarts