Series now loaded directly from database. Removed:
- sync_legacy_series_to_db() from anime_service.py
- Corresponding sync call after directory update in config.py
- Safety nets in initialization_service.py for missing progress IDs
- Move ProgressType import to top-level in auth.py
- Extract suggestion link click handler into attachSuggestionLinkEvents() function
- Reuse handler after search results load
Users were incorrectly redirected to /login during the initial loading phase
before the loading was actually complete. Added loading_started and
loading_complete flags to properly track the initialization state so
the setup redirect middleware knows when it's safe to redirect.
- Add /api/setup/unresolved/done endpoint to mark phase complete
- NFO scan now runs after series sync during initialization
- Middleware redirects to /login after setup complete (was /loading)
- Done button allows skipping folder resolution with redirect to NFO scan phase
- Add SearchFolderRequest model for optional custom search query
- Update search endpoint to use custom query if provided
- Add search-again input field in UI for custom queries
- Increment search_attempts counter on re-search
- Remove nfo_scan and media_scan from loading page steps (no longer shown in UI)
- Remove perform_nfo_scan_if_needed calls from fastapi_app and auth.py
- Always redirect to /setup/unresolved after initialization completes
instead of conditionally checking for unresolved folders
- Fix middleware to allow access to /loading page - let it handle
its own redirect flow via WebSocket events
This ensures users always reach the unresolved folders page after
initial setup to manually configure any unmatched anime series.
When SetupService cannot auto-resolve a provider key for an anime folder,
the folder is now tracked in the new 'unresolved_folders' table instead of
being silently skipped. Users can then resolve these via the new API:
- GET /api/setup/unresolved - list unresolved folders with search suggestions
- POST /api/setup/unresolved/{folder}/resolve - provide key to resolve folder
The SetupService.run() now:
- Tracks unresolved folders instead of skipping them
- Re-creates AnimeSeries for previously unresolved folders that are now resolved
- Includes unresolved count in logs
New files:
- src/server/api/setup_endpoints.py - API endpoints for unresolved management
- tests/unit/test_unresolved_folder_service.py - service and model tests
Modified:
- src/server/database/models.py - add UnresolvedFolder model
- src/server/database/service.py - add UnresolvedFolderService
- src/server/services/setup_service.py - track unresolved folders
- src/server/fastapi_app.py - include setup router
- Add _compute_folder_name helper that deduplicates year (handles cases like 'Name (2023)' not becoming 'Name (2023) (2023)')
- Create anime folder on disk when adding series (not just DB + memory)
- Add rename_folder_if_needed to auto-rename existing folders without year
- Fetch year from aniworld_provider and include in folder as 'Name (YYYY)'
Closes: anime folders now include release year when available from provider
Delete folder_rename_service.py. Stub out get_duplicate_folders API to return
empty response. Update folder_scan_service and tests to skip rename step.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Move src/core/ → src/server/
- Split SerieList.py (531 lines) and series.py (414 lines) into src/server/database/
- Add database/models.py for SQLAlchemy models
- Update all test imports to reflect new structure
- Remove deprecated test files (test_serie_class.py, test_serie_folder_with_year.py)
- Extract rescan logic into new RescanService (src/server/services/rescan_service.py)
- SchedulerService now only handles APScheduler cron scheduling
- Move scheduler sub-services (folder_rename, folder_scan, key_resolution) to scheduler/ folder
- Keep RescanOrchestrator as backward-compatible alias
- Update all imports across api/, server/, and test files
- Create version.py utility to read version from Docker/VERSION
- Replace hardcoded version '1.0.1' with APP_VERSION from version.py
- Add version logging on FastAPI startup
- Use APP_VERSION in health endpoints and template context
- Add DuplicateFolderGroup and DuplicateFoldersResponse Pydantic models
- Add /duplicate-folders GET endpoint for listing pre-existing duplicates
- Add _scan_for_pre_existing_duplicates() function for NFO-based detection
- Add _try_merge_duplicate_group() for auto-merging empty/symlink-only duplicates
- Integrate duplicate detection into validate_and_rename_series_folders workflow
- Skip rename for flagged duplicates to prevent data loss during merge
- Rename function to reflect its legacy status
- Add deprecation warning log on execution
- Update all callers (initialization_service, api/config, fastapi_app)
- Update tests to use new name
- Add deprecation notice to DEVELOPMENT.md
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add ensure_started() to SchedulerService as idempotent entry point.
Start scheduler in auth setup run_initialization() after NFO scan.
Sync anime_directory and start scheduler in config update endpoint.
Add unit and endpoint tests for ensure_started() behavior.
- Add create_minimal_nfo() method to NFOService for fallback when TMDB lookup fails
- Update API endpoints (single and batch) to use minimal NFO fallback on TMDBAPIError
- Document fallback behavior in NFO_GUIDE.md section 3.6
- Add unit tests for minimal NFO creation (11 tests passing)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add _run_startup_health_checks() function in fastapi_app.py
- Check ffmpeg availability (warning)
- Check DNS resolution for aniworld.to and api.themoviedb.org (warning)
- Check anime_directory configuration and writability (error)
- Store startup checks in app.state for health endpoint access
- Add /health/ready endpoint for container orchestrators
- Returns not_ready with 503 when critical failures present
- Includes critical_failures list for debugging
- Update /health endpoint to include startup check results
- Status reflects worst check (error > warning > ok)
- Document health check endpoints in DEVELOPMENT.md
- Add unit tests for startup health checks
- Add unit tests for /health/ready endpoint
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- New _search_with_fallback() method tries multiple strategies:
1. Primary query with year filter (de-DE locale)
2. Alternative titles with ja-JP / en-US locales
3. English search (en-US)
4. Search without year constraint
5. Punctuation-normalized query
- create_nfo() accepts new alt_titles param for Japanese/title fallback
- Better match rate for anime with non-English titles
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Apply the same duplicate-year prevention logic to additional code paths:
- Serie.name_with_year property: skip adding year suffix if name already ends with it
- add_series API endpoint: avoid duplicating year in folder_name_with_year
- Add integration test for Serie.name_with_year idempotency
- Add API test for add_series endpoint year deduplication
Complements the folder_rename_service fix for comprehensive coverage.
- Add folder_scan_enabled boolean field (default false) to SchedulerConfig
- Update data/config.json example with new field
- Add checkbox to setup.html and include in JS payload
- Handle field in auth.py setup endpoint
- Expose field in scheduler API response
- Log and return field in scheduler_service.py
- Update docs/CONFIGURATION.md and docs/ARCHITECTURE.md
- Update index.html UI, app.js and scheduler-config.js handlers
- Verified backward compatibility: old configs load with default False
- 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)
- Add async method list_series_with_filters() to AnimeService
- Refactor list_anime to use service layer instead of direct DB access
- Convert sync database queries to async patterns
- Remove unused series_app parameter from endpoint
- Update test to skip direct unit test (covered by integration tests)
- Mark Issue 1 as resolved in documentation
Critical bug fix: The filter was returning the wrong series because of
a misunderstanding of the episode table semantics.
ISSUE:
- Episodes table contains MISSING episodes (from episodeDict)
- is_downloaded=False means episode file not found in folder
- Original query logic was backwards - returned series with NO missing
episodes instead of series WITH missing episodes
SOLUTION:
- Simplified query to directly check for episodes with is_downloaded=False
- Changed from complex join with count aggregation to simple subquery
- Now correctly returns series that have at least one undownloaded episode
CHANGES:
- src/server/database/service.py: Rewrote get_series_with_no_episodes()
method with corrected logic and clearer documentation
- tests/unit/test_series_filter.py: Updated test expectations to match
corrected behavior with detailed comments explaining episode semantics
- docs/API.md: Enhanced documentation explaining filter behavior and
episode table meaning
TESTS:
All 5 unit tests pass with corrected logic
- Added get_series_with_no_episodes() method to AnimeSeriesService
- Updated list_anime endpoint to support filter='no_episodes' parameter
- Added comprehensive unit tests for the new filtering functionality
- All tests passing successfully
Replace non-existent emit_progress calls with proper ProgressService methods:
- start_progress for starting operations
- update_progress for progress updates
- complete_progress for successful completion
- fail_progress for failures
Convert percentage-based updates to current/total based on ProgressService API
- Create loading.html template with WebSocket-based progress updates
- Update initialization_service to emit progress events via ProgressService
- Modify setup endpoint to run initialization in background and redirect to loading page
- Add /loading route in page_controller
- Show real-time progress for series sync, NFO scan, and media scan steps
- Display completion message with button to continue to app
- Handle errors with visual feedback
- Remove settings.reload() call which doesn't exist in Pydantic BaseSettings
- Manually sync anime_directory and NFO settings from config.json to settings object
- Mirrors the sync logic used in fastapi_app.py lifespan
- Fixes AttributeError: 'Settings' object has no attribute 'reload'
- Create initialization_service.py with shared initialization functions
- Extract setup logic from lifespan and setup endpoint into reusable functions
- Setup endpoint now calls perform_initial_setup() directly
- Lifespan startup calls the same shared functions
- Eliminates code duplication between setup and lifespan
- Ensures consistent initialization behavior regardless of entry point
- Add mark_initial_scan_completed() call to /api/auth/setup endpoint
- Ensures initial_scan_completed flag is set to True after first sync
- Prevents duplicate folder scans on subsequent application startups
- Include error handling to prevent setup failure if marking fails