Droplyst listens to the music around you and saves the tracks it recognizes in a session. At a DJ set, that produces something you can take away: a playlist in the order the songs were first detected.
ShazamKit supplies recognition results. It doesn't decide which results belong in that playlist. A song can keep playing across several recognition windows and each window can identify it successfully. Appending every successful match would give you a list full of the same track.
The part I needed to define was what counts as a new track.
Three ways to recognize the same recording
The capture loop keeps a set of identities it has already seen. For each result, it checks the Shazam ID, the ISRC and a lowercased title-and-artist pair. A match on any of those keys suppresses the result.
Here's the relevant part of the loop, with the callback shortened:
const keys = [
`${result.title.toLowerCase()}|${result.artist.toLowerCase()}`,
result.shazamID,
result.isrc,
].filter(Boolean) as string[];
if (keys.some((key) => knownTrackIds.has(key))) return;
for (const key of keys) knownTrackIds.add(key);
appendTrack(result);Registering all the available identities gives the next result more than one way to match. A changed display title can still match an existing ISRC. A result without recording IDs can still match its title and artist.
The text key is less precise. Lowercasing doesn't resolve spelling differences. Two versions with the same title and artist can collapse into one entry.
The order is the order of first detection
Consider this sample session:
| Recognition event | Saved session |
|---|---|
| Track A arrives | A |
| Track A arrives again | A |
| Track B arrives | A, B |
| Track A is deliberately played again later | A, B |
The last row is the interesting one. My identity set covers the whole session. It doesn't expire when the music changes. An intentional replay therefore looks like another duplicate.
That suits a playlist where each recognized track appears once. It doesn't produce a complete performance log. I wouldn't use this data to claim exactly what played, how often it played, or when a song started: recognition timestamps describe detections.
Supporting a performance timeline would require another concept: an occurrence of a recording. The same recording could then have multiple occurrences. A time-based reset alone would be awkward because a long track and a later replay can both produce widely separated matches.
Pausing must preserve the identity history
Resuming a saved session rebuilds the known-identity set from its stored tracks. Starting recognition with an empty set would let the song still playing get added again immediately.
The saved tracks and the capture loop consequently have to agree on identity. A screen can say “continue session,” but that promise depends on restoring the history used by the recognition logic, as well as restoring the rows shown on screen.
Export introduces a different identity problem
Once the session is captured, a Shazam match still needs a corresponding Spotify recording. My export flow searches by ISRC first, then falls back to title and artist. It resolves tracks in session order and sends playlist writes in batches of up to 100 URIs.
The text fallback accepts the first search result. That can select another version, so successful recognition and successful export are separate results. An unmatched track stays in the session and is reported as missing from the export.
I can improve Spotify matching without changing how recognition builds a session. Checking alternate versions, for example, would change which recording gets exported while leaving the identity keys and session order alone.