v2.3.2
What's Changed
Subscription result pages previously made uncached Deezer image lookups and full Lidarr library downloads on every page load. This release eliminates both bottlenecks — result pages now load in milliseconds.
Performance
- Redis-cached artist images: All Deezer artist image lookups route through a shared Redis cache (7-day positive TTL, 1-hour negative TTL, bounded concurrency of 5). Cold cache warms on first use; subsequent requests served in microseconds.
- Persistent
imageUrlon results: The subscription worker now stores the resolved artist image URL directly on each result row at creation time. Read paths serve the stored URL immediately — no per-request Deezer calls. - Shared
LidarrCachewith coalescing + stale-while-revalidate: All routes share a single per-URLLidarrCacheinstance. Parallel refresh callers share one in-flight promise (no stampede). First call blocks; subsequent stale reads serve immediately and refresh in the background. - Boot-time Lidarr cache warmup: On startup, the API warms the shared cache for all active Lidarr connections — the first result request never pays the full library download cost.
- Server-side pagination:
GET /api/subscriptions/:id/resultsdefaults to 50 results per page (cap 200) withlimit/offsetparams, replacing unbounded full-table loads.
Frontend
- Parallel react-query subscription detail page: Rewritten with parallel
useSubscriptionDetail,useSubscriptionRuns, anduseSubscriptionResultshooks — no waterfall fetches, no uncached calls on load. Row-level approve/reject mutations update the cache surgically without a full page refetch.
Fixes
LidarrCacheconcurrent refresh stampede: Multiple simultaneous requests no longer each trigger independent Lidarr library downloads.- Input validation:
limitandoffsetparams are now clamped to safe ranges (offset ≥ 0, 1 ≤ limit ≤ 200).
Tests
- API: 1309 / 1309 tests pass
- Web: 255 / 255 tests pass