Files
Aniworld/tests/unit/test_database_models.py
Lukas c84f968916 fix(queue): dedupe episodeDict at read boundary + trust server response
The 'episodes added to download queue never shown' symptom has two
layered causes that masked each other:

1. The 'episodes' table has no UNIQUE constraint on
   (series_id, season, episode_number), so historical scans can leave
   duplicate rows behind. AnimeSeries.episodeDict iterated the
   SQLAlchemy 'episodes' relationship without deduping, so the dict
   exposed duplicate entries to list_missing() and the queue UI.
   The frontend forwarded the duplicated episode list verbatim to
   POST /api/queue/add; the backend's pending-episode dedup then
   rejected every duplicate as 'already pending' and the user saw
   'Skipped 44 duplicate episodes, Added 0'.

2. selection-manager.downloadSelected counted 'episodes.length'
   (the input array) instead of data.added_items.length (the
   server-confirmed count). Combined with the backend returning
   success on an empty add, the user saw a misleading 'Added 44
   episode(s)' toast for an empty queue.

Fix: dedupe at the read boundary. The episodeDict property now
filters duplicate (season, episode_number) pairs from both the
DB-loaded relationship and the legacy _episode_dict_cache path.
Existing duplicate rows in the user's DB are inert — the read
filter makes them invisible to the rest of the stack. The
frontend now trusts the server response, logs a console warning
when an input list shrinks to zero added items, and shows an
accurate toast.

Tests:
- TestEpisodeDictDedup class with 4 regression tests covering:
  * duplicate relationship rows deduped
  * is_downloaded rows still filtered out
  * _episode_dict_cache path also deduped (set by scanners/loaders
    that may store duplicates)
  * dedup is per-(season, ep_num), preserving legitimate
    same-ep-num-across-different-seasons entries

Verified manually against the user's backup DB: 'erased' has 44
duplicate rows in the episodes table; episodeDict now returns
{1: [1..12]} instead of {1: [1,1,2,2,3,3,3,3,...]}, matching the
12-episode canonical list.
2026-09-15 20:46:31 +02:00

26 KiB