- Remove premature auth redirect in unresolved.html fetchUnresolved()
- Add /api/setup/ to middleware exempt paths
- Unresolved page now loads without auth token (part of setup flow)
- Only redirect to login on 401 (expired token) or when all folders resolved
- loading.html: check for unresolved folders before redirecting, go to /login if none
- unresolved.html: redirect to /loading instead of / after skip/timeout
- add docs/NAVIGATION.md navigation flow documentation
- 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.
- Add check for existing series by key in SetupService.run to skip duplicates
- Fix Path construction in initialization_service.py cleanup function
- Update unit tests to mock get_by_key and get_series_app
After initial setup completes, the loading page now checks for unresolved
folders before showing completion. If any unresolved exist, redirects
to /setup/unresolved so users can manually resolve provider keys.
Without this fix, users with unresolved folders only saw the loading
screen with no way to access the unresolved page.
- Add /setup/unresolved page for manual provider key resolution
- Integrate unresolved check into setup wizard flow
- Auto-redirect to unresolved page if folders need resolution
After initial setup scan, folders that couldn't be auto-resolved
are now tracked and can be resolved manually via the GUI.
Endpoints:
- GET /api/setup/unresolved - list unresolved folders
- POST /api/setup/unresolved/{folder}/resolve - resolve with provider key
- POST /api/setup/unresolved/{folder}/search - re-search for suggestions
- DELETE /api/setup/unresolved/{folder} - delete without adding
When the search provider returns a link like 'shinobi-no-ittoki' instead of
'/anime/stream/shinobi-no-ittoki', the key was not being extracted and all
folders were marked as unresolved.
Now handles both link formats:
- URL format: '/anime/stream/key' -> extract key
- Direct format: 'key' -> use as-is
Also added debug logging for both resolution paths to aid troubleshooting.
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 _normalize_title() to strip anime suffixes (TV, OVA, Movie, etc.)
- Add _titles_match() using SequenceMatcher for similarity (threshold 0.85)
- Replace exact string match with fuzzy match to fix skipped folders
- Add debug logging for title mismatches and multiple results
- Set LOG_LEVEL=DEBUG in docker-compose.yml
- Fix _resolve_key_via_search to use 'title' instead of 'name'
- Extract key from 'link' field URL (e.g., /anime/stream/naruto -> naruto)
- Skip folders with unresolved keys instead of crashing with 'Series key cannot be empty'
- Update tests to use correct field names (title/link)
SetupService.run() now checks each anime folder for tvshow.nfo,
logo.png, and poster/fanart images instead of using hardcoded
defaults. Provider key resolution via search is unchanged.
Extract SetupService class from initialization_service to handle:
- Scan data/ folder subdirectories
- Extract title and year from folder names (YYYY pattern)
- Create AnimeSeries records in database
- Resolve provider keys via search (single exact match)
Updates _scan_folders_to_database() to delegate to SetupService.run().
Adds comprehensive unit tests for SetupService.
- 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
- Add nfo_scan_after_rescan config option (default: true)
- Implement year caching in AniworldLoader and EnhancedAniWorldLoader
- Make get_year abstract method in base provider
- Run NFO validation/creation after scheduled rescan completes
- Add _YearDict cache to avoid re-extracting year from HTML
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>
Convert handle_network_failure and handle_download_failure from instance methods to static methods. Hardcode retry params (max_retries, delays) instead of using instance state. Improves testability and removes implicit dependencies.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Previously, the method created a SerieList instance which only loads
from database, not from data files. Now reads data files directly
and parses JSON to create AnimeSeries objects.
Also added _load_data_file helper function and fixed logger.warning
calls to use proper format strings instead of keyword arguments.
Updated unit tests to use real temp directories instead of mocks.
- Add _scan_folders_to_database() - iterates anime_directory subdirs
- Extract title/year from folder names via (YYYY) pattern
- Resolve provider key via search when single match found
- Create AnimeSeries records for new folders only
- Add corresponding unit tests
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move nfo_models, tmdb_client, nfo_generator, nfo_mapper from
scattered temp directories into single src/server/nfo/ package.
Update all imports to reflect new structure.
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)
RescanService was thin wrapper. Its logic (rescan, auto-download, folder
scan, WebSocket broadcasts) moved into SchedulerService as private methods.
RescanService and its module deleted.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- 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
Add migrate_schema_if_needed() to handle adding missing columns to existing
tables for backward compatibility. Automatically adds legacy_key_cleanup_completed
BOOLEAN column to system_settings table if missing, preventing 'no such column'
errors on startup for existing databases.