npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

musicbrainz-api

v0.19.1

Published

MusicBrainz API client for reading and submitting metadata

Downloads

1,538

Readme

Node.js CI CodeQL NPM version npm downloads Coverage Status Codacy Badge Known Vulnerabilities DeepScan grade Discord bundlejs.com badge

musicbrainz-api

A MusicBrainz-API-client for reading and submitting metadata.

Features

  • Access Metadata: Retrieve detailed metadata from the MusicBrainz database.
  • Submit metadata: Easily submit new metadata to MusicBrainz.
  • Smart throttling: Implements intelligent throttling, allowing bursts of requests while adhering to MusicBrainz rate limits.
  • TypeScript Definitions: Fully typed with built-in TypeScript definitions for a seamless development experience.

Compatibility

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

Requirements

  • Node.js: Requires Node.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.

Support the Project

If you find this project useful and would like to support its development, consider sponsoring or contributing:

Getting Started

Identifying Your Application

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.

Submitting metadata

If you plan to use this module for submitting metadata, please ensure you comply with the MusicBrainz Code of conduct/Bots.

Example Usage

Importing the Library

import { MusicBrainzApi } from 'musicbrainz-api';

const mbApi = new MusicBrainzApi({
    appName: 'my-app',
    appVersion: '0.1.0',
    appContactInfo: '[email protected]',
});

[!NOTE] See also CommonJS backward compatibility

Configuration Options

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: '[email protected]',

    // 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);

Accessing MusicBrainz Data

The MusicBrainz API allows you to look up various entities. Here’s how to use the lookup function:

Lookup MusicBrainz Entities

MusicBrainz API documentation: XML Web Service/Version 2 Lookups

Lookup Function

const artist = await mbApi.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 |

Browse artist

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 |

Browse collection

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 |

Browse events

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 |

Browse instruments

const instruments = await mbApi.browse('event', query);

| Query argument | Query value | |-----------------------|--------------------|
| query.collection | Collection MBID |

Browse labels

const labels = await mbApi.browse('label', query);

| Query argument | Query value | |--------------------|-----------------|
| query.area | Area MBID | | query.collection | Collection MBID | | query.release | Release MBID |

Browse places

const places = await mbApi.browse('place', query);

| Query argument | Query value | |--------------------|-----------------|
| query.area | Area MBID | | query.collection | Collection MBID |

Browse recordings

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 |

Browse releases

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 |

Browse release-groups

const releaseGroups = await mbApi.browse('release-group',query);

| Query argument | Query value | |--------------------|-----------------|
| query.artist | Artist MBID | | query.collection | Collection MBID | | query.release | Release MBID |

Browse series

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 |

Browse works

const works = await mbApi.browse('work');

| Query argument | Query value | |--------------------|-----------------|
| query.artist | Artist MBID | | query.xollection | Collection MBID |

Browse urls

const urls = await mbApi.browse('url');

| Query argument | Query value | |--------------------|-----------------|
| query.artist | Artist MBID | | query.xollection | Collection MBID |

Search (query)

Implements XML Web Service/Version 2/Search.

There are different search fields depending on the entity.

Search function

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:
  • query {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 find any recordings of 'We Will Rock You' by Queen:

const query = 'query="We Will Rock You" AND arid:0383dadf-2a4e-4d10-a46a-e9e041da8eb3';
const result = await mbApi.search('release-group', {query});
Example: search Île-de-France
 mbApi.search('area', 'Île-de-France');
Example: search release by barcode

Search a release with the barcode 602537479870:

 mbApi.search('release', {query: {barcode: 602537479870}});
Example: search by object

Same as previous example, but automatically serialize parameters to search query

 mbApi.search('release', 'barcode: 602537479870');
Example: search artist by artist name

Search artist:

const result = await mbApi.search('artist', {query: 'Stromae'});
Example: search release-group by artist name

Search release-group:

const result = await mbApi.search('release-group', {query: 'Racine carrée'});
Example: search release-group by release-group and an artist

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

Submitting data via XML POST may be done using personal MusicBrainz credentials.

Submit ISRC code using XML POST

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);

Submitting data via user form-data

For all of the following function you need to use a dedicated bot account.

Submitting ISRC via post user form-data

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);

Submit recording URL

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');

Cover Art Archive API

This library also supports the Cover Art Archive API.

Fetch Release Cover Art

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
})();

Release Group Cover Art

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
})();

CommonJS backward compatibility

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: '[email protected]',
    });

    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.