Two AI-review findings from Cin (kettui) on the source-picker PR:
1. Soulseek handoff from global widget went through metadata flow
_gsNavigateToSearchPage(query, 'soulseek') wrote the query into
#enhanced-search-input and dispatched an input event. The Search
page controller's activeSource was whatever its default was
(spotify, deezer, etc.), so the debounced submitQuery ran the
enhanced /api/enhanced-search flow instead of the raw Soulseek
file search. The `src` parameter was effectively ignored.
Fix: when src === 'soulseek', pre-fill #downloads-search-input
directly and click the Search page's Soulseek icon. The icon click
triggers the controller's onSoulseekSelected callback, which owns
the section swap and re-runs performDownloadsSearch against the
value we just wrote to the basic input.
2. Stale in-flight requests cleared loadingSources after fast retype
createSearchController._fetchSource awaits the fetch result, then
unconditionally mutates state.loadingSources / state.sources in
the settle and catch blocks. When a user typed "abc" → fetch
started → typed "abcd" before the first fetch returned, the
second submitQuery aborted the first fetch and started its own.
The first fetch's catch (AbortError) then ran and cleared
loadingSources for that source — wiping the spinner the new
request had just set, and causing a brief flash of empty/error
state while the new fetch was still in flight.
Fix: monotonic _requestSeq token. Each _fetchSource call captures
the next value (++_requestSeq). Settle / catch blocks (and the
YouTube NDJSON streaming loop) bail before mutating shared state
if requestId !== _requestSeq. Existing abortCtrl behavior unchanged
— this is a layered defense for the catch-clobber pattern that
abort alone can't prevent.