# Spotify Service

Integration with the [Spotify](https://www.spotify.com) streaming platform, providing lookup and search functionality for artists, albums, and tracks via the [Spotify Web API](https://developer.spotify.com/documentation/web-api).

## Supported Features

- ✅ URL Parsing
- ✅ Lookup by URL
- ✅ Search by Name
- ✅ Lookup by UPC
- ✅ Lookup by ISRC
- ✅ Health check

## Link and ID Formats

Spotify links are matched against the following patterns:

- Web URL: `https://open.spotify.com/{type}/{id}` (also `play.spotify.com`)
  - An optional locale segment is supported, e.g. `https://open.spotify.com/intl-de/album/{id}`
- URI: `spotify:{type}:{id}`

Where `{type}` is one of `artist`, `album`, or `track`, and `{id}` is the Spotify base-62 ID (e.g. `7gsWAHLeT0w7es6FofOXk1`).

## API Documentation

- **Base URL**: `https://api.spotify.com/v1/`
- **Lookup endpoints**: `GET /artists/{id}`, `GET /albums/{id}`, `GET /tracks/{id}`
- **Search endpoint**: `GET /search` (used for name search, and for UPC/ISRC lookup via `q=upc:...` / `q=isrc:...`)

Most requests pass a `market` (ISO country) parameter so results are localized to the user's country (see `constants.ts` for the supported `COUNTRIES`).

### Authentication

The integration authenticates with the **OAuth 2.0 Client Credentials** flow (server-to-server, no user context):

- Requires the `SPOTIFY_CLIENT_ID` and `SPOTIFY_CLIENT_SECRET` environment variables.
- A bearer token is requested from `https://accounts.spotify.com/api/token` and cached in memory until it expires, then transparently refreshed (see `api/getToken.ts`).

## Quota & Rate Limits

This integration runs against a Spotify app that has been granted **Extended Quota Mode**.

Spotify apps start in **Development mode**, which has lower rate limits and restricts access to a small allow-list of users. **Extended Quota Mode** is granted by Spotify after review and provides the higher rate limits required for production traffic, without the development-mode user restrictions. The credentials configured via `SPOTIFY_CLIENT_ID` / `SPOTIFY_CLIENT_SECRET` belong to such an app.

Rate limits are still enforced (calculated over a rolling ~30 second window); exceeding them returns `429 Too Many Requests` with a `Retry-After` header. To stay comfortably within the quota even in Extended Quota Mode, batch album resolution caps the number of in-flight requests:

- `lookupAlbumsApi` resolves each album with an individual `GET /albums/{id}` request and limits concurrency to **5** parallel requests (via [`p-limit`](https://www.npmjs.com/package/p-limit)).

## Known Limitations

- The deprecated `GET /albums?ids=` batch endpoint is no longer used; album batches are resolved with concurrency-limited per-id lookups instead. Albums that are no longer available resolve to a `404` and are omitted from the result.
- The Spotify album search response does not include UPCs, so the dedicated `/albums` endpoint re-fetches full album records (which include `upc` and `isExplicit`) for IDs returned by search.
