Spotify Stage
The Spotify Stage matches your Play data with the Spotify catalog, using the Spotify Web API. If the match is confident enough then Multi-Scrobbler uses it to correct and fill-in missing information in your Play data.
This Stage is useful for standardizing your Scrobble’s Play data, regardless of the Source it is coming from, and is a good complement (or alternative) to the Musicbrainz Stage if you’d prefer matches to come from Spotify’s own catalog.
Configuration
Section titled “Configuration”API Setup
Section titled “API Setup”This Stage uses Spotify’s API to search/lookup the Spotify catalog. This does not require a user to log in – only an app clientId/clientSecret is needed. Create a Spotify application if you don’t already have one (the same application used for the Spotify Source can be reused here).
{ "transformers": [ { "type": "spotify", "name": "MySpotify", "data": { "clientId": "787c921a2a2ab42320831aba0c8f2fc2", "clientSecret": "ec42e09d5ae0ee0f0816ca151008412a" }, } ]}Rate Limiting
rate can be used to configure how many requests are made to the Spotify API, defined by max number of requests within timespan of N seconds (default 10 req/1s):
{ "type": "spotify", "name": "MySpotify", "data": { "clientId": "787c921a2a2ab42320831aba0c8f2fc2", "clientSecret": "ec42e09d5ae0ee0f0816ca151008412a", "rate": { "requests": 10, "perTime": 1 } },}Stage Configuration
Section titled “Stage Configuration”All of the properties found in Matching with Spotify section are configured in Stage Configuration as defaults.
These are all also optional so you can use the Spotify Transform stage without configuring any of this.
{ "transformers": [ { "type": "spotify", "name": "MySpotify", "data": { "clientId": "787c921a2a2ab42320831aba0c8f2fc2", "clientSecret": "ec42e09d5ae0ee0f0816ca151008412a" }, "defaults": { "score": 0.6, "deprioritizeCompilations": true } } ]}Rules and Hooks
Section titled “Rules and Hooks”Add your Stage to a Source or Client by specifying it in a Hook:
[ { "name": "MySubsonic", "data": { /* ... */}, "options": { "playTransform": { "preCompare": [ { "type": "spotify", "name": "MySpotify" } ] } } }]Each Stage Rule (title/artists/albumArtists/album/duration/meta/art) works the same way as it does for the Musicbrainz Stage: either a boolean specifying whether the transformed data should be used for this field, or a when condition.
ENV Configuration
Section titled “ENV Configuration”Your Spotify Stage can be configured using ENV Config by specifying client/secret and, optionally, combining different presets.
Client ID and Secret are the only required configuration:
- Client Id => ENV
SPOTIFY_TRANSFORM_CLIENT_IDor ENVSPOTIFY_CLIENT_IDfrom the Spotify Source - Client Secret => ENV
SPOTIFY_TRANSFORM_CLIENT_SECRETor ENVSPOTIFY_CLIENT_SECRETfrom the Spotify Source
To configure stage defaults use ENV SPOTIFY_TRANSFORM_PRESETS= with a comma-delimited list of presets you wish to apply. If SPOTIFY_TRANSFORM_PRESETS is not set the stage will use defaults.
searchIsrc- Restricts search methods toisrconly (default isisrcandbasic)missingFields- Only run transform ifalbum,artist,title, ordurationare missing in datamissingIds- Only run transform if spotify ids are missing in datamissingIsrc- Only run transform ifisrcis missing in datamissingArt- Only run transform ifartis missing in datadecomp- Deprioritize compilations when ranking matches
More than one preset can be applied, in which case they combine.
Example
services: multi-scrobbler: # ... environment: # ... - SPOTIFY_CLIENT_ID=787c921a2a2ab42320831aba0c8f2fc2 - SPOTIFY_CLIENT_SECRET=ec42e09d5ae0ee0f0816ca151008412a # ...- 1.only runs transform if album, artists, title, duration, or art are missing in data and only searches by isrc
Finally, use ENV *_TRANSFORMS=spotify on each Source/Client you wish to apply this stage to. This applies the stage in the preCompare Hook with all Rules enabled.
The * stands for the prefix used for each Source/Client’s ENV keys. Refer to the individual Source/Client Configuration sections to find this. Example:
- All Subsonic Source ENVs look like
SUBSONIC_USER=myuseretc… - Use
SUBSONIC_TRANSFORMS=spotify
Example Full Docker Deploy with ENV Configuration
services: multi-scrobbler: image: foxxmd/multi-scrobbler container_name: multi-scrobbler environment: - SPOTIFY_CLIENT_ID=787c921a2a2ab42320831aba0c8f2fc2 - SPOTIFY_CLIENT_SECRET=ec42e09d5ae0ee0f0816ca151008412a - JELLYFIN_URL=192.168.0.110:8096 - JELLYFIN_APIKEY=c9fae8756fbf481ebd9c5bb56b - JELLYFIN_USER=MyUser
- MALOJA_API_KEY=myApiKey
volumes: - "./config:/config" ports: - "9078:9078" restart: unless-stopped- 1.only runs transform if art or fields are missing in data and only searches by isrc
- 2.applies spotify Stage to preCompare of Jellyfin source
- 3.maloja receives enhanced scrobble from Jellyfin
To use the configured ENV stage in Rules and Hooks with File/AIO config either omit name or specify it as "name": "MSEnv".
Matching with Spotify
Section titled “Matching with Spotify”Matching your Scrobble’s Play data with a result from Spotify is comprised of two steps:
- Searching Spotify using parts of your Scrobble as queries
- Ranking matched results to select the desired match
Searching
Section titled “Searching”Should MS Search?
Section titled “Should MS Search?”Before MS begins a search it checks if your Scrobble data already contains:
- A track title, artists, album, and duration
- All spotify IDs and an ISRC
If it already has all required data types then the entire Spotify Stage is skipped. If any are missing then a search is performed.
Define which data types are required using:
searchWhenMissing- A list containing any of:album,title,artists,duration,isrc, andidsidsis any missing spotify id (track, artists, albumArtists, and album ids)- the default when
searchWhenMissingis not defined is:album,artists,title, andduration
forceSearch(defaultfalse) - Force searching even if all required data is present
Search Methods
Section titled “Search Methods”Multi-scrobbler searches for a Spotify match using, in order, up to two methods. Use searchOrder to control which methods run and in what order:
// ...your Stage Configuration"defaults": { "searchOrder": ["isrc", "basic"] }ISRC (isrc)
If your Scrobble data contains an ISRC then Multi-scrobbler searches Spotify’s catalog using this ID.
If the ISRC is present on more than one Spotify album/track (which happens often IE singles, re-releases, and compilation appearances of the same recording all share an ISRC) then the results are ranked using fuzzy matching against your scrobble’s existing album/artist data to pick the best candidate.
Album, Artist, and Title Fields (basic)
Searches Spotify using any/all available text fields from your scrobble: Album, primary Artist, and Title. Results are always ranked using fuzzy matching since Spotify’s text search does not otherwise guarantee an accurate/confident result.
Biasing Search Results with market and locale
market (an ISO 3166-1 alpha-2 country code) can be set to bias/limit search results to what is available in a specific market:
Example
{ "type": "spotify", "name": "MySpotify", "data": {/* */}, "defaults": { // ... "market": "US" }}locale (in ISO-639-1_ISO-3166-1 format, EX en_US, ja_JP) can additionally be set to try to bias which translation of a localized catalog name (artist/album/track) Spotify returns for a match:
Example
{ "type": "spotify", "name": "MySpotify", "data": {/* */}, "defaults": { // ... "locale": "en_US" }}Ranking
Section titled “Ranking”Spotify’s search results do not carry a confidence/similarity score so Multi-scrobbler fuzzy-matches every candidate against your original scrobble’s title/artist(s)/album to:
- disambiguate between multiple candidates (EX an ISRC present on more than one album)
- for
basicsearch results only, determine whether any candidate is a confident enough match to use at all
Each candidate is scored between 0 and 1 based on how similar its title/artist(s)/album are to your original scrobble. Set score to change the minimum score a basic-search candidate must have to be used. Default is 0.6. This has no effect on isrc matches, which are always used.
You can bias which of title/artist/album contributes most to a candidate’s score with titleWeight, artistWeight, and albumWeight (defaults are 0.4/0.3/0.3, respectively):
// ...your Stage Configuration"defaults": { "titleWeight": 0.4, "artistWeight": 0.3, "albumWeight": 0.3 }Deprioritize Compilations
Section titled “Deprioritize Compilations”Spotify catalogs many recordings across multiple compilation albums (Greatest Hits, movie soundtracks that reuse a song, etc…) in addition to their “proper” studio album. If you’d prefer matches to avoid compilation albums when a better alternative exists, enable deprioritizeCompilations:
// ...your Stage Configuration"defaults": { "deprioritizeCompilations": true }This does not exclude compilations – it only lowers their score relative to other candidates, so a compilation can still be used if it’s the only match found.
Best Practices
Section titled “Best Practices”Caching
Section titled “Caching”You should setup metadata caching to reduce API calls, improve transform performance, and reduce memory usage when using this stage.
Using Partial Match
Section titled “Using Partial Match”Use Rules to apply Spotify match data selectively. This is useful if you don’t want your scrobble’s Artist/Title/Album modified but still want Spotify IDs or ISRC defined for Clients or other Stages to leverage them.
Example
[ { "name": "MySubsonic", "data": { /* ... */}, "options": { "playTransform": { "preCompare": [ { "type": "spotify", "name": "MySpotify", "title": false, "artists": false, "album": false, "albumArtists": false, "meta": true } ] } } }]Logging
Section titled “Logging”If Spotify is not returning matches, or the resulting enhanced Scrobble is not what you expected, enable Debug Mode to help diagnose issues with the Spotify API and Scrobble enhancement.
If you have multiple Modification Stages and need to see the diff for your Play between each Stage, enable "log": "all" in the individual Modification Stage, as described for the Musicbrainz Stage.