- 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)
- Add migration_legacy_files_completed flag to SystemSettings model
- Create legacy_file_migration service to migrate series from key/data files
- Integrate legacy migration into initialization_service startup flow
- Add integration tests for legacy file migration
- Update DATABASE.md documentation with migration details
- Fix various test and service issues (nfo_repair, tmdb_client, download_service)
- Add test_database_schema unit tests
Use the database as the authoritative source for missing-episode lists so
that episodes marked is_downloaded=True are never shown as missing, even
when the in-memory state is stale.
Key changes:
- EpisodeService.get_by_series() gains only_missing flag
- AnimeService uses DB-backed episodeDict and preserves downloaded episodes
during sync, skipping them when adding/removing missing episodes
- DownloadService broadcasts series_updated after marking an episode downloaded
so the frontend reflects the change immediately
- Frontend filters out series with zero missing episodes client-side and
fixes renderSeries to respect the active filter
- Unit tests updated to assert the broadcast is sent
Retry count and queue status were in-memory only and lost on
restart, so failed downloads could not be safely resumed and
permanently-failed episodes silently blocked re-queueing via the
episode-id unique index.
- Add status + retry_count columns to DownloadQueueItem
- Replace unique(episode_id) with unique(episode_id, status) so
permanently_failed rows do not block new pending entries
- Add PERMANENTLY_FAILED to DownloadStatus enum
- Persist retry_count on each failure; mark permanently_failed once
max_retries reached
- QueueRepository reads status/retry_count from DB instead of
defaulting to PENDING/0
- Stop double-incrementing retry_count in retry_failed_items;
increment only happens in _process_download on failure
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Change _remove_episode_from_missing_list to set is_downloaded=True
and populate file_path via EpisodeService.mark_downloaded, instead of
deleting the Episode row. Preserves download history so queries can
distinguish series with downloaded episodes from completely unwatched
series.
- Pass serie_folder to construct file_path
- Look up series_id via AnimeSeriesService.get_by_key
- Update tests to mock mark_downloaded path
- Document episode lifecycle in docs/DEVELOPMENT.md
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- In-memory dedup in add_to_queue() using _pending_by_episode dict
- Batch-local dedup via seen_in_batch set (handles duplicates within single call)
- Database unique index on episode_id via __table_args__
- 5-minute cooldown in _auto_download_missing() to prevent rapid re-triggers
- Updated _add_to_pending_queue() and _remove_from_pending_queue() to track episode keys
- Added TestQueueDeduplication with 4 test cases
- Updated DEVELOPMENT.md and TESTING.md with queue dedup docs
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fixed _remove_episode_from_missing_list to also update in-memory
Serie.episodeDict and refresh series_list
- Added _remove_episode_from_memory helper method
- Enhanced logging for download completion and episode removal
- Added 5 unit tests for missing episode removal
- Updated infrastructure.md with queue database schema and storage details
- Updated instructions.md to mark migration task as completed
- No deprecated JSON code remains in codebase
- Created QueueRepository adapter in src/server/services/queue_repository.py
- Refactored DownloadService to use repository pattern instead of JSON
- Updated application startup to initialize download service from database
- Updated all test fixtures to use MockQueueRepository
- All 1104 tests passing
- Updated DownloadService to use 'serie_id' (provider key) for identification
- Changed 'serie_folder' from Optional to required in models (DownloadItem, DownloadRequest)
- Removed incorrect fallback logic that used serie_id as folder name
- Enhanced docstrings to clarify purpose of each identifier field:
* serie_id: Provider key (e.g., 'attack-on-titan') for lookups
* serie_folder: Filesystem folder name (e.g., 'Attack on Titan (2013)') for file operations
- Updated logging to reference 'serie_key' for clarity
- Fixed all unit tests to include required serie_folder field
- All 25 download service tests passing
- All 47 download model tests passing
- Updated infrastructure.md with detailed documentation
- Marked Task 3.1 as completed in instructions.md
Benefits:
- Clear separation between provider identifier and filesystem path
- Prevents confusion from mixing different identifier types
- Consistent with broader series identifier standardization effort
- Better error messages when required fields are missing