- Notifications
You must be signed in to change notification settings - Fork42
JavaScript MusicBrainz API client for reading and submitting metadata
License
Borewit/musicbrainz-api
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
A MusicBrainz-API-client for reading and submitting metadata.
- Access Metadata: Retrieve detailed metadata from theMusicBrainz database.
- Submit metadata: Easily submit new metadata toMusicBrainz.
- Smart throttling: Implements intelligent throttling, allowing bursts of requests while adhering toMusicBrainz rate limits.
- TypeScript Definitions: Fully typed with built-inTypeScript definitions for a seamless development experience.
Module: version 8 migrated fromCommonJS topure ECMAScript Module (ESM).The distributed JavaScript codebase is compliant with theECMAScript 2020 (11th Edition) standard.
Note
See alsoCommonJS backward compatibility
- Node.js: RequiresNode.js version 16 or higher.
- Browser: Can be used in browser environments when bundled with a module bundler (not actively tested).
Note
We are looking into making this package usable in the browser as well.
If you find this project useful and would like to support its development, consider sponsoring or contributing:
Buy me a coffee:
MusicBrainz requires all API clients toidentify their application.Ensure you set the User-Agent header by providingappName
,appVersion
, andappContactInfo
when configuring the client.This library will automatically handle this for you.
If you plan to use this module for submitting metadata, please ensure you comply withthe MusicBrainz Code of conduct/Bots.
import{MusicBrainzApi}from'musicbrainz-api';constmbApi=newMusicBrainzApi({appName:'my-app',appVersion:'0.1.0',appContactInfo:'user@mail.org',});
Note
See alsoCommonJS backward compatibility
constconfig={// Optional: MusicBrainz bot account credentialsbotAccount:{username:'myUserName_bot',password:'myPassword',},// Optional: API base URL (default: 'https://musicbrainz.org')baseUrl:'https://musicbrainz.org',// Required: Application detailsappName:'my-app',appVersion:'0.1.0',appMail:'user@mail.org',// Optional: Proxy settings (default: no proxy server)proxy:{host:'localhost',port:8888,},// Optional: Disable rate limiting (default: false)disableRateLimiting:false,};constmbApi=newMusicBrainzApi(config);
The MusicBrainz API allows you to look up various entities. Here’s how to use the lookup function:
MusicBrainz API documentation:XML Web Service/Version 2 Lookups
constartist=awaitmbApi.lookup('artist','ab2528d9-719f-4261-8098-21849222a0f2');
Arguments:
- entity:
'area'
|'artist'
|'collection'
|'instrument'
|'label'
|'place'
|'release'
|'release-group'
|'recording'
|'series'
|'work'
|'url'
|'event'
- MBID(MusicBrainz identifier)
- query
Query argument | Query value |
---|---|
query.collection | Collection MBID |
constartists=awaitmbApi.browse('artist',query);
Query argument | Query value |
---|---|
query.area | Area MBID |
query.collection | Collection MBID |
query.recording | Recording MBID |
query.release | Release MBID |
query.release-group | Release-group MBID |
query.work | Work MBID |
constcollections=awaitmbApi.browse('collection',query);
Query argument | Query value |
---|---|
query.area | Area MBID |
query.artist | Artist MBID |
query.editor | Editor MBID |
query.event | Event MBID |
query.label | Label MBID |
query.place | Place MBID |
query.recording | Recording MBID |
query.release | Release MBID |
query.release-group | Release-group MBID |
query.work | Work MBID |
constevents=awaitmbApi.browse('event',query);
Query argument | Query value |
---|---|
query.area | Area MBID |
query.artist | Artist MBID |
query.collection | Collection MBID |
query.place | Place MBID |
constinstruments=awaitmbApi.browse('event',query);
Query argument | Query value |
---|---|
query.collection | Collection MBID |
constlabels=awaitmbApi.browse('label',query);
Query argument | Query value |
---|---|
query.area | Area MBID |
query.collection | Collection MBID |
query.release | Release MBID |
constplaces=awaitmbApi.browse('place',query);
Query argument | Query value |
---|---|
query.area | Area MBID |
query.collection | Collection MBID |
constrecordings=awaitmbApi.browse('recording',query);
Query argument | Query value |
---|---|
query.artist | Area MBID |
query.collection | Collection MBID |
query.release | Release MBID |
query.work | Work MBID |
constreleases=awaitmbApi.browse('release',query);
Query argument | Query value |
---|---|
query.area | Area MBID |
query.artist | Artist MBID |
query.editor | Editor MBID |
query.event | Event MBID |
query.label | Label MBID |
query.place | Place MBID |
query.recording | Recording MBID |
query.release | Release MBID |
query.release-group | Release-group MBID |
query.work | Work MBID |
constreleaseGroups=awaitmbApi.browse('release-group',query);
Query argument | Query value |
---|---|
query.artist | Artist MBID |
query.collection | Collection MBID |
query.release | Release MBID |
constseries=awaitmbApi.browse('series');
Query argument | Query value |
---|---|
query.area | Area MBID |
query.artist | Artist MBID |
query.editor | Editor MBID |
query.event | Event MBID |
query.label | Label MBID |
query.place | Place MBID |
query.recording | Recording MBID |
query.release | Release MBID |
query.release-group | Release-group MBID |
query.work | Work MBID |
constworks=awaitmbApi.browse('work');
Query argument | Query value |
---|---|
query.artist | Artist MBID |
query.xollection | Collection MBID |
consturls=awaitmbApi.browse('url');
Query argument | Query value |
---|---|
query.artist | Artist MBID |
query.xollection | Collection MBID |
ImplementsXML Web Service/Version 2/Search.
There are different search fields depending on the entity.
Searches can be performed using the generic search function:query(entity: mb.EntityType, query: string | IFormData, offset?: number, limit?: number): Promise<entity>
Arguments:
- Entity type, which can be one of:
artist
:search fieldslabel
:search fieldsrecording
:search fieldsrelease
:search fieldsrelease-group
:search fieldswork
:search fieldsarea
:search fieldsurl
:search fields
query {query: string, offset: number, limit: number}
query.query
: supports the full Lucene Search syntax; you can find a detailed guide atLucene Search Syntax. For example, you can set conditions while searching for a name with the AND operator.query.offset
: optional, return search results starting at a given offset. Used for paging through more than one page of results.limit.query
: optional, an integer value defining how many entries should be returned. Only values between 1 and 100 (both inclusive) are allowed. If not given, this defaults to 25.
For example, to search forrelease-group:"We Will Rock You" byQueen:
constquery='query=artist:"Queen" AND release:"We Will Rock You"';constresult=awaitmbApi.search('release-group',{query});
mbApi.search('area','Île-de-France');
Search a release with the barcode 602537479870:
mbApi.search('release',{query:{barcode:602537479870}});
Same as previous example, but automatically serialize parameters to search query
mbApi.search('release','barcode: 602537479870');
Search artist:
constresult=awaitmbApi.search('artist',{query:'Stromae'});
Search release-group:
constresult=awaitmbApi.search('release-group',{query:'Racine carrée'});
Search a combination of a release-group and an artist.
constresult=awaitmbApi.search('release-group',{artist:'Racine carrée',releasegroup:'Stromae'});
Submitting data via XML POST may be done using personal MusicBrainz credentials.
Using theXML ISRC submission API.
constmbid_Formidable='16afa384-174e-435e-bfa3-5591accda31c';constisrc_Formidable='BET671300161';constxmlMetadata=newXmlMetadata();constxmlRecording=xmlMetadata.pushRecording(mbid_Formidable);xmlRecording.isrcList.pushIsrc(isrc_Formidable);awaitmbApi.post('recording',xmlMetadata);
For all of the following function you need to use a dedicated bot account.
Use with caution, and only on a test server, it may clear existing metadata has side effect.
constmbid_Formidable='16afa384-174e-435e-bfa3-5591accda31c';constisrc_Formidable='BET671300161';constrecording=awaitmbApi.lookup('recording',mbid_Formidable);// Authentication the http-session against MusicBrainz (as defined in config.baseUrl)constsucceed=awaitmbApi.login();assert.isTrue(succeed,'Login successful');// To submit the ISRC, the `recording.id` and `recording.title` are requiredawaitmbApi.addIsrc(recording,isrc_Formidable);
constrecording=awaitmbApi.lookup('recording','16afa384-174e-435e-bfa3-5591accda31c');constsucceed=awaitmbApi.login();assert.isTrue(succeed,'Login successful');awaitmbApi.addUrlToRecording(recording,{linkTypeId:LinkType.stream_for_free,text:'https://open.spotify.com/track/2AMysGXOe0zzZJMtH3Nizb'});
Actually a Spotify-track-ID can be submitted easier:
constrecording=awaitmbApi.lookup('recording','16afa384-174e-435e-bfa3-5591accda31c');constsucceed=awaitmbApi.login();assert.isTrue(succeed,'Login successful');awaitmbApi.addSpotifyIdToRecording(recording,'2AMysGXOe0zzZJMtH3Nizb');
This library also supports theCover Art Archive API.
import{CoverArtArchiveApi}from'musicbrainz-api';constcoverArtArchiveApiClient=newCoverArtArchiveApi();asyncfunctiongetReleaseCoverArt(releaseMbid,coverType=''){try{constcoverInfo=awaitcoverArtArchiveApiClient.getReleaseCovers(releaseMbid,coverType);console.log(`Cover info for${coverType||'all covers'}`,coverInfo);}catch(error){console.error(`Failed to fetch${coverType||'all covers'}:`,error);}}(async()=>{constreleaseMbid='your-release-mbid-here';// Replace with actual MBIDawaitgetReleaseCoverArt(releaseMbid);// Get all coversawaitgetReleaseCoverArt(releaseMbid,'front');// Get best front coverawaitgetReleaseCoverArt(releaseMbid,'back');// Get best back cover})();
import{CoverArtArchiveApi}from'musicbrainz-api';constcoverArtArchiveApiClient=newCoverArtArchiveApi();asyncfunctiongetCoverArt(releaseGroupMbid,coverType=''){try{constcoverInfo=awaitcoverArtArchiveApiClient.getReleaseGroupCovers(releaseGroupMbid,coverType);console.log(`Cover info for${coverType||'all covers'}`,coverInfo);}catch(error){console.error(`Failed to fetch${coverType||'all covers'}:`,error);}}(async()=>{constreleaseGroupMbid='your-release-group-mbid-here';// Replace with actual MBIDawaitgetCoverArt(releaseGroupMbid);// Get all coversawaitgetCoverArt(releaseGroupMbid,'front');// Get best front coverawaitgetCoverArt(releaseGroupMbid,'back');// Get best back cover})();
I recommend CommonJS projects to consider upgrading their project to ECMAScript Module (ESM).Please continue reading how to usemusicbrainz-api in a CommonJS project.
Using Node.js ≥ 22, which is support loading ESM module via require, you can use:
const{ MusicBrainzApi}=require('musicbrainz-api');
Other CommonJS projects have to usedynamic import to load themusicbrainz-api pure ESM module:
asyncfunctionrun(){// Dynamically loads the ESM module in a CommonJS projectconst{ MusicBrainzApi}=awaitimport('musicbrainz-api');};run();
This is known not to work in TypeScript CommonJS projects, as the TypeScript compiler, in my opinion,incorrectly converts thedynamic importtorequire()
. To perform the dynamic import in TypeScript, you can useload-esm:
import{loadEsm}from'load-esm';asyncfunctionrun(){// Dynamically loads the ESM module in a TypeScript CommonJS projectconst{ MusicBrainzApi}=awaitloadEsm<typeofimport('musicbrainz-api')>('musicbrainz-api');};run();
This project is licensed under theMIT License. Feel free to use, modify, and distribute as needed.
About
JavaScript MusicBrainz API client for reading and submitting metadata