tag filter: persist selection, no empty flash, sort left (#1218)
* tag filter: persist selection, no empty flash, selected tags sort left
- Persist activeTags in localStorage so selections survive page refresh
- Restore saved tags on init (TracksCache + TagFilter SvelteSet)
- Don't clear tracks array in setTags() — keep stale data visible while
loading to avoid the blank flash (loading spinner still shows)
- Sort selected tags to the front of the chip row
The "slow clear" feeling was caused by the empty flash: setTags([])
cleared tracks to [] immediately, then the unfiltered /tracks/ request
takes 250-1200ms (atprotofans.validate_supporter external HTTP call).
Now old tracks stay visible during the fetch.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* perf: cache atprotofans validation in Redis, parallelize with DB work
The validate_supporter external HTTP call to atprotofans.com was taking
80-1100ms per request and running sequentially after all DB queries.
Two fixes:
1. Redis cache (5-min TTL) for supporter validation results — subsequent
page loads skip the external call entirely.
2. Start supporter validation as an asyncio task immediately after getting
the track list, so it runs concurrently with batch aggregations, PDS
resolution, and image resolution instead of after them.
Also adds visual loading indicator (opacity dim) when track list is
refreshing from a tag filter change.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use MagicMock for httpx response in atprotofans tests
httpx Response.json() is synchronous — AsyncMock wraps it as a
coroutine which causes the call to silently fail.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
authored by