Fix production database schema mismatch where downloadSource and
primaryFailureFallback columns were missing from SystemSettings table.
Root cause: Migration gap between squashed init migration and production
database setup timing.
Fix: Idempotent migration adds both columns if they don't exist:
- downloadSource TEXT NOT NULL DEFAULT 'soulseek'
- primaryFailureFallback TEXT NOT NULL DEFAULT 'none'
- Add MAX_LIMIT=10000 constant to prevent DoS attacks while supporting
large libraries through pagination
- Apply MAX_LIMIT to /library/artists, /library/albums, /library/tracks
- Add trackCount field to artists endpoint (fixes "Most Tracks" sort)
- Add /library/tracks/shuffle endpoint for server-side shuffle
- Update frontend to use server-side shuffle instead of fetching 10k tracks
The shuffle endpoint uses Fisher-Yates algorithm and samples random tracks
for large libraries to avoid loading the entire database into memory.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove Math.min(..., 1000) hard cap on /library/artists endpoint
- Remove Math.min(..., 1000) hard cap on /library/albums endpoint
- Add offset parameter and total count to /library/tracks endpoint
- Rewrite useLibraryData hook for true server-side pagination
- Update library page to fetch pages on demand instead of client-side slicing
- Disable pagination buttons during loading to prevent race conditions
This allows libraries of any size to be fully browsable. Previously,
users with 10,000+ songs were capped at seeing only 500 items.
Fixes#12🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fixed player seek flicker on podcasts (30s skip buttons)
- Added dual-layer seek lock mechanism to prevent stale time updates
- Optimized cached podcast seeking (direct seek before reload fallback)
- Large skips now execute immediately for responsive feel
- Mood mix performance optimizations