Skip to main content

Musicbrainz Stage

The Musicbrainz Stage matches your Play data with the MusicBrainz database. If the match score is high enough then Multi-Scrobbler uses the match 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.

Even if you have have strong opinions about the way your existing music is already tagged/organized you should consider adding the Musicbrainz Stage to your Sources, if only to benefit from adding MBIDs to scrobbled metadata.

Why Should I Prefer MusicBrainz?

More Than Mainstream Data

The MusicBrainz database contains

  • 37 million+ tracks
  • 5 million+ albums
  • 2.7 million+ artists

in over 200 languages, contributed by 10,000+ editors each year with many more users voting on edits.

The database covers a much wider range of music than most commercial services since it isn't restricted by licensing or incentivized to prioritize mainstream music due to business interests. You are much more likely to find data for obscure, indie, and international artists.

As The Artist Intended

While some large services (Spotify) may be more consistent in data structure, the MusicBrainz equivalent data is likely to be more true to the way the Artist originally intended since individuals can devote effort to individual artists. A fan of an artist is much more likely to "get it right" for their favorite band than a corporate business trying to do the least amount of work for the largest result.

tip

If you are using ENV Config for multi-scrobbler and just want a quick and easy setup, skip to ENV Configuration.

tip

Set up Valkey Caching to cache Musicbrainz API calls for faster processing.

Configuration

API Setup

To avoid rate limiting, MusicBrainz requires API users to identify themself using a User-Agent that contains an email or URL. You must set this in the data for your stage configuration in your AIO Config:

config.json
{
// ...
"transformers": [
{
"type": "musicbrainz",
"name": "MyMB",
"data": {
"apis": [
{
"contact": "contact@mydomain.com"
}
]
},
}
]
}
Additional Musicbrainz Servers

Other, or additional, Musicbrainz Servers/Mirrors can be added to the API configuration. If more than one server is defined then multi-scrobbler will round-robin load balance API calls.

Use url to define the base URL of the Musicbrainz server to use. If url is not defined multi-scrobbler assumes it is the primary Musicbrainz server, https://musicbrainz.org.

Example of multiple servers:

config.json
{
// ...
"transformers": [
{
"type": "musicbrainz",
"name": "MyMB",
"data": {
"apis": [
{
"contact": "contact@mydomain.com"
// uses default Musicbrainz server https://musicbrainz.org
},
// additional server
{
"contact": "contact@mydomain.com",
"url": "https://my.mb.mirror.domain.com"
}
]
},
}
]
}

Stage Configuration

All of the properties found in Matching with Musicbrainz section are configured in Stage Configuration as defaults.

Example:

config.json
{
// ...
"transformers": [
{
"type": "musicbrainz",
"name": "MyMB",
"data": {
"apis": [
{
"contact": "contact@mydomain.com"
}
],
"defaults": {
"releaseStatusPriority": ["official"],
"fallbackArtistSearch": "native",
"releaseAllowEmpty": true
}
},
}
]
}

Rules

Each Rule should be either a boolean, specifying if the transformed data should be used for this field, or a when condition:

{
"type": "musicbrainz",
"name": "MyMB"
// ...
"title": false, // will not apply any changes to Play title
"artists": {
"when": {/* ... */}, // will only apply changes to Play artists if "when" is satisfied
/* ... */
},
"album": true // will always apply changes to Play album
"meta": true // adds MusicBrainz MBIDs to scrobble data
}

ENV Configuration

The general configuration shown above can also be configured from a selection of presets using ENV Config for individual Sources/Clients.

You must always include the MB_CONTACT ENV to identify your application:

MB_CONTACT=contact@mydomain.com

To configure stage defaults use MB_PRESETS with a comma-delimited list of presets you wish to apply. More than one preset can be applied, in which case they combine. You must choose at least one of the presets below:

  • default - Applies no defaults. This is the same as using no options from Matching With Musicbrainz
  • sensible - Applies the Sensible Default configuration for sorting releases
  • native - Applies fallbackArtistSearch: native for Artist Extraction if the first search fails to find matches
  • aggressive - Applies Free Text Search fallbackFreeTextSearch: true if all other searches fail

Finally, use ENV *_TRANSFORMS=musicbrainz on each Source/Client you wish to apply this stage to. This applies the stage in the preTransform 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=myuser etc...
  • Use SUBSONIC_TRANSFORMS=musicbrainz
Example Full Docker Deploy with ENV Configuration

Using Jellyfin + Maloja example from Quickstart:

services:
multi-scrobbler:
image: foxxmd/multi-scrobbler
container_name: multi-scrobbler
environment:
- MB_CONTACT=contact@mydomain.com
- MB_PRESETS=sensible,native # creates sensible defaults with native fallback searching

- JELLYFIN_URL=192.168.0.110:8096
- JELLYFIN_APIKEY=c9fae8756fbf481ebd9c5bb56b
- JELLYFIN_USER=MyUser
- JELLYFIN_TRANSFORMS=musicbrainz # applies musicbrainz Stage to preTransform of Jellyfin source

- MALOJA_URL=http://192.168.0.100:42010 # maloja receives enhanced scrobble from Jellyfin
- MALOJA_API_KEY=myApiKey


volumes:
- "./config:/config"
ports:
- "9078:9078"
restart: unless-stopped

Matching with Musicbrainz

note

All properties found in this section are optional.

If you just want a sensible default for configuraion refer to the Best Practices section.

Matching your Scrobble's Play data with a result from Musicbrainz is comprised of two steps:

  • Searching Musicbrainz using parts of your Scrobble as queries
  • Refining matched results to select the desired/allowed match

Both steps have separate configuration.

Searching

The first step is making search queries to the Musicbrainz database to try to get potential candidates. Multi-scrobbler uses the title, artist(s), and album from your Scrobble data to query for matches.

Musicbrainz agressively normalizes these fields in its database which means that if your Scrobble data contains major innaccuracies or phrases fields in a non-normal way, it's possible Musicbrainz won't find any matches. This is a more common occurrence when trying to match Scrobble data from Sources that don't support multiple artist data, like Subsonic and Last.fm.

Examples of Bad Data

Last.fm Scrobble returns an Artist in the title and combines two artists into one string:

{
"title": "Endless Possibility (feat. Wheatus)",
"artists": ["Bowling For Soup & Punk Rock Factory"]
}

The corresponding Musicbrainz Recording has all artists separated and no artist in the title:

{
"title": "Endless Possibility",
"artists": ["Bowling For Soup", "Punk Rock Factory", "Wheatus"]
}

If a normal search using all the fields mentioned above does not return any matches Multi-scrobbler can try additional searches with modified queries:

Album Only

If your Scrobble data contains a title, artist(s), and an album (all three fields) then Multi-scrobbler will automatically retry the search using only title and album.

Artist Extraction

If...

  • Album Only returns no results or did not run due to missing an album
  • Your scrobble data contains only one artist string
  • fallbackArtistSearch is set in Stage Configuration

Then Multi-scrobbler will attempt to extract multiple artists from your artist and track string. This is not automatic. You must set fallbackArtistSearch to enable this additional search.

fallbackArtistSearch can be set to Native or Naive mode:

Native (native) mode uses an aggressive configuration of the Native Stage to extract artists using common delimiters and common "joined" artist patterns from the artist and title string of your Scrobble data.

tip

If you already have a Native Stage configured you should use that instead, running it before the Musicbrainz stage.

Native Mode Example
{
"title": "Endless Possibility (feat. Wheatus)",
"artists": ["Bowling For Soup & Punk Rock Factory, My Cool Band"]
}
  • Extracts Bowling For Soup Punk Rock Factory My Cool Band from artist string
  • Extracts Wheatus from title string
    • Removes (feat. Wheatus) from title string because it found an artist there

Resulting data used for Musicbrainz search:

{
"title": "Endless Possibility",
"artists": ["Bowling For Soup", "Punk Rock Factory", "My Cool Band", "Wheatus"]
}

Stage Configuration example:

// ...
"defaults": {
// ...
"fallbackArtistSearch": "native"
}

Free Text

If both Album Only and Artist Extraction searches fail to return results you can additionally enable Free Text search. This will search Musicbrainz for all text of your Scrobble data artist/title/album, without constraint. This is not automatic. You must set fallbackFreeTextSeach: true to enable this additional search.

warning

Free text search is unconstrained which means that Musicbrainz will match text in any part of a Recording (artist, release, or recording field), regardless of where it is found. This may lead to results that are unexpected and undesired.

If you know your Source's Play data is well organized you should not enable this. Free Text search should only be used if:

  • your music is not well organized or
  • there may be many alternative titles/artists for the music you listen to (such as with psuedo-releases)
  • you can tolerate that matches may not be accurate for releases.
    • Generally, if you keep score high then matched releases should at least be the right artist or what you would expect within a reason, as a match. The release may not be the one you actually listened to but it would be "close enough".

Stage Configuration example:

// ...
"defaults": {
// ...
"fallbackFreeTextSearch": true
}

Refining

Score

Each match returned by MusicBrainz contains a numeric score representing how close it was to the search parameters. Set score in configuration to set a minimum score that must be met by matches. Default is 90.

{
// ...
"score": 90 // matches must score 90 or higher to be considered
}

Filtering

There are several attributes associated with the Release a Recording (individual Track/song) belongs to that you may be interested in controlling. MS can use these attributes to filter what the final Recording selected to match against your Play data is.

An easy way to think about this:

  • Do you prefer Albums, Singles, or EPs?
  • Do you always want to use an official album release, or are bootleg or cancelled albums okay to use?
  • Should a track that belongs to a Compilation album be allowed to match?
  • What country do you prefer an album release to be from?
Release Attributes

These attributes (attribute_name in config) are:

  • Release Status (releaseStatus) - Is this release/album/ep official, promotional, bootleg, etc...
  • Release Group Primary Type (releaseGroupPrimaryType) - Is this release an Album, Single, EP, etc...
  • Release Group Secondary Type (releaseGroupSecondaryType) - Is this release a compilation, soundtrack, remix, etc...
  • Release Country (releaseCountry) - What ISO2 country was this released in? US, GB, MX, etc...
    • MusicBrainz uses the special code XW to represent a "Worldwide" release AKA release not made specifically for a country

Each of the above attributes can be used to filter matches using allow (explicitly include) or deny (exclude) terms. The correct property name for each is like so:

[attribute_name]Allow = [...]
[attribute_name]Deny

EX to explicitly allow only release status "official"

"releaseStatusAllow": ["official"]

EX to exclude compilations

"releaseGroupSecondaryTypeDeny": ["compilation"]

Empty Releases

Sometimes a Recording may not have any associated Releases. This may be because there is not enough information about the Recording yet, or it was never included on an actual Release.

You may want to filter the majority of your matches by releases but allow matching a Recording that has no releases to begin with. To allow this set releaseAllowEmpty to true in configuration:

// ...
"defaults": {
// ...
"releaseAllowEmpty": true // don't remove a match during filtering just because it has no releases
}

Sorting

Each Release Attribute has one additional property that can be used to rank releases based on the order of the values you give it. This is the priority property.

After matches have been filtered, the remaining matches will have their releases sorted. Release with an attribute that does not match are not removed, but they are sorted lower than releases that do match.

Sorting can be a good alternative to filtering: with filters there is a possibility your filters may eliminate all matches; if you want to ensure that some match will be used then sorting can ensure that the best choice out of those given will always be used, without accidentally ending up with no choice.

Sorting can be used instead of filters, or in conjunction with filters, it's your choice.

In configuration:

[attribute_name]Priority = [...]

EX to prefer "official" releases over everything else

"releaseStatusPriority": ["official"]

EX to prefer albums, then singles, over everything else

"releaseGroupPrimaryTypePriority": ["album", "single"]

If a rule is not present then multi-scrobbler defaults it to true.

Best Practices

Sensible Default

Generally, the Musicbrainz Stage can be used without any of the optional configuration and you should still see good results from matches. The top scored match is, anecdotally, good enough for correcting and filling in surface-level play data like Title and Artist names.

For a more opinionated match that will mirror what you would expect from data from large music services:

{
// use official release over anything else
"releaseStatusPriority": ["official"],
// prefer album, then single, then ep
"releaseGroupPrimaryTypePriority": ["album", "single", "ep"],
// prefer worldwide release
"releaseCountryPriority": ["XW"]
}

Consider adding Artist Extraction in Native Mode if any of your Sources do not support multiple artists or your music collection is not tagged well.

{
// add the line below to the sensible defaults above
// (don't forget commas)
"fallbackArtistSearch": "native"
}

Filter Considerations

When using your own filters consider:

  • Prefer deny over allow
    • Releases come in all kinds of formats. Since allow is explicit you may filter out your desired match without realizing it (correct data except for release type). Or the Musicbrainz data for a higher scored match may be appropriate but you did not include it, exhaustively.
  • Prefer Sorting over Filtering
    • Sorting does not eliminate any matches. It is, generally, better to get some match than it is to have your Play data completely uncorrected because filtering eliminated all matches

Using Partial Match

Use Rules to apply MusicBrainz match data selectively.

If you know that your music collection is well organized and you do not want to change the artists/title/album etc... sent to a Client, you can still benefit from matches by only applying MBIDs using meta so that any Client that supports Musicbrainz data (Koito, Tealfm, Listenbrainz, Rocksky) can still get that data.

Example
subsonic.json
[
{
"name": "MySubsonic",
"data": { /* ... */},
"options": {
"playTransform": {
"preCompare": [
{
"type": "musicbrainz",
"name": "MyMB",
"title": false,
"artists": false,
"album": false,
"albumArtists": false,
"meta": true
}
]
}
}
}
]

Logging

If

  • Musicbrainz is not returning matches
  • Multi-scrobbler is using the wrong match
  • or the resulting enhanced Scrobble is not what you expected

Enable logging by turning on Debug Mode to help diagnose any issues with the Musicbrainz API and Scrobble enhancement. Before creating an issue please enable logging and include any logs with your issue as this is needed to debug.

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.

Example

In a Subsonic File Config:

subsonic.json
[
{
"name": "MySubsonic",
"data": { /* ... */},
"options": {
"playTransform": {
"log": "all",
"preCompare": [
{
"type": "musicbrainz",
"name": "MyMB",
}
]
}
}
}
]

Examples

Minimal

Example

Your AIO Config:

config.json
{
// ...
"transformers": [
{
"type": "musicbrainz",
"name": "MyMB",
"data": {
"apis": [
{
"contact": "contact@mydomain.com"
}
]
},
}
]
}

In a Subsonic File Config:

subsonic.json
[
{
"name": "MySubsonic",
"data": { /* ... */},
"options": {
"playTransform": {
"preCompare": [
{
"type": "musicbrainz",
"name": "MyMB"
}
]
}
}
}
]

Sensible Default

Using the config shown in Sensible Default with File/AIO config, instead of ENV Config.

Example

Your AIO Config:

config.json
{
// ...
"transformers": [
{
"type": "musicbrainz",
"name": "MyMB",
"data": {
"apis": [
{
"contact": "contact@mydomain.com"
}
]
},
"defaults": {
"releaseStatusPriority": ["official"],
"releaseGroupPrimaryTypePriority": ["album", "single", "ep"],
"releaseCountryPriority": ["XW"],
"fallbackArtistSearch": "native"
}
}
]
}

In a Subsonic File Config:

subsonic.json
[
{
"name": "MySubsonic",
"data": { /* ... */},
"options": {
"playTransform": {
"preCompare": [
{
"type": "musicbrainz",
"name": "MyMB"
}
]
}
}
}
]

Add Metadata Only (No Scrobble Modification)

If you do not want your scrobble data to be modified (artists/album/title) but still want to benefit from associating the scrobble with a Musicbrainz match (for Scrobble Clients like Tealfm, Rocksky, and Koito), then use Partial Match rules to specify only meta to be updated.

Example

Your AIO Config:

config.json
{
// ...
"transformers": [
{
"type": "musicbrainz",
"name": "MyMB",
"data": {
"apis": [
{
"contact": "contact@mydomain.com"
}
]
},
"defaults": {
// maybe something like Sensible Default?
}
}
]
}

In a Jellyfin File Config:

subsonic.json
[
{
"name": "MyJellyfin",
"data": { /* ... */},
"options": {
"playTransform": {
"preCompare": [
{
"type": "musicbrainz",
"name": "MyMB",
"title": false,
"artists": false,
"album": false,
"albumArtists": false,
"meta": true // only update scrobble metadata with MBIDs
}
]
}
}
}
]