
Security News
NVD Concedes Inability to Keep Pace with Surging CVE Disclosures in 2025
Security experts warn that recent classification changes obscure the true scope of the NVD backlog as CVE volume hits all-time highs.
musicbrainz-api
Advanced tools
A MusicBrainz-API-client for reading and submitting metadata.
Module: version 8 migrated from CommonJS to pure ECMAScript Module (ESM). The distributed JavaScript codebase is compliant with the ECMAScript 2020 (11th Edition) standard.
[!NOTE] See also CommonJS backward compatibility
[!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 to identify their application.
Ensure you set the User-Agent header by providing appName
, appVersion
, and appContactInfo
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 with the MusicBrainz Code of conduct/Bots.
import { MusicBrainzApi } from 'musicbrainz-api';
const mbApi = new MusicBrainzApi({
appName: 'my-app',
appVersion: '0.1.0',
appContactInfo: 'user@mail.org',
});
[!NOTE] See also CommonJS backward compatibility
const config = {
// Optional: MusicBrainz bot account credentials
botAccount: {
username: 'myUserName_bot',
password: 'myPassword',
},
// Optional: API base URL (default: 'https://musicbrainz.org')
baseUrl: 'https://musicbrainz.org',
// Required: Application details
appName: '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,
};
const mbApi = new MusicBrainzApi(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
const artist = await mbApi.lookup('artist', 'ab2528d9-719f-4261-8098-21849222a0f2');
Arguments:
'area'
| 'artist'
| 'collection'
| 'instrument'
| 'label'
| 'place'
| 'release'
| 'release-group'
| 'recording'
| 'series'
| 'work'
| 'url'
| 'event'
Query argument | Query value |
---|---|
query.collection | Collection MBID |
const artists = await mbApi.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 |
const collections = await mbApi.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 |
const events = await mbApi.browse('event', query);
Query argument | Query value |
---|---|
query.area | Area MBID |
query.artist | Artist MBID |
query.collection | Collection MBID |
query.place | Place MBID |
const instruments = await mbApi.browse('event', query);
Query argument | Query value |
---|---|
query.collection | Collection MBID |
const labels = await mbApi.browse('label', query);
Query argument | Query value |
---|---|
query.area | Area MBID |
query.collection | Collection MBID |
query.release | Release MBID |
const places = await mbApi.browse('place', query);
Query argument | Query value |
---|---|
query.area | Area MBID |
query.collection | Collection MBID |
const recordings = await mbApi.browse('recording', query);
Query argument | Query value |
---|---|
query.artist | Area MBID |
query.collection | Collection MBID |
query.release | Release MBID |
query.work | Work MBID |
const releases = await mbApi.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 |
const releaseGroups = await mbApi.browse('release-group',query);
Query argument | Query value |
---|---|
query.artist | Artist MBID |
query.collection | Collection MBID |
query.release | Release MBID |
const series = await mbApi.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 |
const works = await mbApi.browse('work');
Query argument | Query value |
---|---|
query.artist | Artist MBID |
query.xollection | Collection MBID |
const urls = await mbApi.browse('url');
Query argument | Query value |
---|---|
query.artist | Artist MBID |
query.xollection | Collection MBID |
Implements XML 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:
artist
: search fieldslabel
: search fieldsrecording
: search fieldsrelease
: search fieldsrelease-group
: search fieldswork
: search fieldsarea
: search fieldsurl
: search fieldsquery {query: string, offset: number, limit: number}
query.query
: supports the full Lucene Search syntax; you can find a detailed guide at Lucene 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 for release-group: "We Will Rock You" by Queen:
const query = 'query=artist:"Queen" AND release:"We Will Rock You"';
const result = await mbApi.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:
const result = await mbApi.search('artist', {query: 'Stromae'});
Search release-group:
const result = await mbApi.search('release-group', {query: 'Racine carrée'});
Search a combination of a release-group and an artist.
const result = await mbApi.search('release-group', {artist: 'Racine carrée', releasegroup: 'Stromae'});
Submitting data via XML POST may be done using personal MusicBrainz credentials.
Using the XML ISRC submission API.
const mbid_Formidable = '16afa384-174e-435e-bfa3-5591accda31c';
const isrc_Formidable = 'BET671300161';
const xmlMetadata = new XmlMetadata();
const xmlRecording = xmlMetadata.pushRecording(mbid_Formidable);
xmlRecording.isrcList.pushIsrc(isrc_Formidable);
await mbApi.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.
const mbid_Formidable = '16afa384-174e-435e-bfa3-5591accda31c';
const isrc_Formidable = 'BET671300161';
const recording = await mbApi.lookup('recording', mbid_Formidable);
// Authentication the http-session against MusicBrainz (as defined in config.baseUrl)
const succeed = await mbApi.login();
assert.isTrue(succeed, 'Login successful');
// To submit the ISRC, the `recording.id` and `recording.title` are required
await mbApi.addIsrc(recording, isrc_Formidable);
const recording = await mbApi.lookup('recording', '16afa384-174e-435e-bfa3-5591accda31c');
const succeed = await mbApi.login();
assert.isTrue(succeed, 'Login successful');
await mbApi.addUrlToRecording(recording, {
linkTypeId: LinkType.stream_for_free,
text: 'https://open.spotify.com/track/2AMysGXOe0zzZJMtH3Nizb'
});
Actually a Spotify-track-ID can be submitted easier:
const recording = await mbApi.lookup('recording', '16afa384-174e-435e-bfa3-5591accda31c');
const succeed = await mbApi.login();
assert.isTrue(succeed, 'Login successful');
await mbApi.addSpotifyIdToRecording(recording, '2AMysGXOe0zzZJMtH3Nizb');
This library also supports the Cover Art Archive API.
import { CoverArtArchiveApi } from 'musicbrainz-api';
const coverArtArchiveApiClient = new CoverArtArchiveApi();
async function getReleaseCoverArt(releaseMbid, coverType = '') {
try {
const coverInfo = await coverArtArchiveApiClient.getReleaseCovers(releaseMbid, coverType);
console.log(`Cover info for ${coverType || 'all covers'}`, coverInfo);
} catch (error) {
console.error(`Failed to fetch ${coverType || 'all covers'}:`, error);
}
}
(async () => {
const releaseMbid = 'your-release-mbid-here'; // Replace with actual MBID
await getReleaseCoverArt(releaseMbid); // Get all covers
await getReleaseCoverArt(releaseMbid, 'front'); // Get best front cover
await getReleaseCoverArt(releaseMbid, 'back'); // Get best back cover
})();
import { CoverArtArchiveApi } from 'musicbrainz-api';
const coverArtArchiveApiClient = new CoverArtArchiveApi();
async function getCoverArt(releaseGroupMbid, coverType = '') {
try {
const coverInfo = await coverArtArchiveApiClient.getReleaseGroupCovers(releaseGroupMbid, coverType);
console.log(`Cover info for ${coverType || 'all covers'}`, coverInfo);
} catch (error) {
console.error(`Failed to fetch ${coverType || 'all covers'}:`, error);
}
}
(async () => {
const releaseGroupMbid = 'your-release-group-mbid-here'; // Replace with actual MBID
await getCoverArt(releaseGroupMbid); // Get all covers
await getCoverArt(releaseGroupMbid, 'front'); // Get best front cover
await getCoverArt(releaseGroupMbid, 'back'); // Get best back cover
})();
For legacy CommonJS projects needing to load the music-metadata
ESM module, you can use the loadMusicMetadata
function:
const { loadMusicBrainzApi } = require('musicbrainz-api');
(async () => {
// Dynamically loads the ESM module in a CommonJS project
const {MusicBrainzApi} = await loadMusicBrainzApi();
const mbApi = new MusicBrainzApi({
appName: 'my-app',
appVersion: '0.1.0',
appContactInfo: 'user@mail.org',
});
const releaseList = await mbApi.search('release', {query: {barcode: 602537479870}});
for(const release of releaseList.releases) {
console.log(release.title);
}
})();
[!NOTE] The
loadMusicMetadata
function is experimental.
FAQs
MusicBrainz API client for reading and submitting metadata
The npm package musicbrainz-api receives a total of 343 weekly downloads. As such, musicbrainz-api popularity was classified as not popular.
We found that musicbrainz-api demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Security experts warn that recent classification changes obscure the true scope of the NVD backlog as CVE volume hits all-time highs.
Security Fundamentals
Attackers use obfuscation to hide malware in open source packages. Learn how to spot these techniques across npm, PyPI, Maven, and more.
Security News
Join Socket for exclusive networking events, rooftop gatherings, and one-on-one meetings during BSidesSF and RSA 2025 in San Francisco.