SonEx MusicBrainz Client

A lightweight, Elixir client for the MusicBrainz API v2.

Hex.pmDocumentation

Installation

Add son_ex_musicbrainz_client to your list of dependencies in mix.exs:

def deps do
  [
    {:son_ex_musicbrainz_client, "~> 0.2.1"}
  ]
end

Then run:

mix deps.get

Configuration

User Agent (Required for Production)

MusicBrainz requires a user agent identifying your application. Configure it in config/config.exs:

config :son_ex_musicbrainz_client,
  user_agent: "MyApp/1.0 (contact@example.com)"

HTTP Options (Optional)

You can configure additional HTTP options for the Req client:

config :son_ex_musicbrainz_client,
  http_options: [
    # Add custom options here
    receive_timeout: 30_000
  ]

Usage

Lookup by MBID

Retrieve a specific entity using its MusicBrainz Identifier (MBID):

# Look up an artist
{:ok, artist} = SonEx.MusicBrainz.lookup(:artist, "5b11f4ce-a62d-471e-81fc-a69a8278c7da")
artist["name"]
# => "Nirvana"

# Look up a release with additional data
{:ok, release} = SonEx.MusicBrainz.lookup(
  :release,
  "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  inc: ["artists", "labels", "recordings"]
)

# Look up a recording
{:ok, recording} = SonEx.MusicBrainz.lookup(:recording, "recording-mbid-here")
recording["title"]
# => "Smells Like Teen Spirit"

Supported entity types for lookup::area, :artist, :event, :genre, :instrument, :label, :place, :recording, :release, :release_group, :series, :work, :url

Common options:

Browse Relationships

Discover entities related to another entity:

# Browse all releases by an artist
{:ok, result} = SonEx.MusicBrainz.browse(
  :release,
  [artist: "5b11f4ce-a62d-471e-81fc-a69a8278c7da"],
  limit: 50
)
result["releases"]
# => [%{"id" => "...", "title" => "Nevermind"}, ...]

# Browse recordings on a release
{:ok, result} = SonEx.MusicBrainz.browse(
  :recording,
  [release: "release-mbid"],
  inc: ["artist-credits"]
)

# Browse artists from an area
{:ok, result} = SonEx.MusicBrainz.browse(
  :artist,
  [area: "area-mbid"],
  offset: 100,
  limit: 25
)

# Browse release groups by artist
{:ok, result} = SonEx.MusicBrainz.browse(
  :release_group,
  [artist: "artist-mbid"],
  type: "album"
)

Common browse relationships by entity:

Common options:

Search

Full-text search using Lucene query syntax:

# Search for artists
{:ok, result} = SonEx.MusicBrainz.search(:artist, "artist:nirvana AND country:US")
result["artists"]
# => [%{"id" => "...", "name" => "Nirvana", "score" => 100}, ...]
result["count"]
# => 15

# Search for releases with pagination
{:ok, result} = SonEx.MusicBrainz.search(
  :release,
  "release:nevermind AND artist:nirvana",
  limit: 10,
  offset: 0
)

# Search for recordings
{:ok, result} = SonEx.MusicBrainz.search(
  :recording,
  "recording:\"Smells Like Teen Spirit\" AND artist:nirvana"
)

# Complex search with multiple criteria
{:ok, result} = SonEx.MusicBrainz.search(
  :artist,
  "artist:beatles AND country:GB AND type:group",
  limit: 25
)

Supported entity types for search::area, :artist, :event, :genre, :instrument, :label, :place, :recording, :release, :release_group, :series, :work, :url

Common search fields by entity:

See the MusicBrainz Search Documentation for complete field references.

Common options:

Response Format

All functions return native Elixir maps parsed from JSON:

# Successful response
{:ok, data} = SonEx.MusicBrainz.lookup(:artist, "mbid-here")
# data is a map: %{"id" => "...", "name" => "...", ...}

# Error responses are passed through from Req
{:error, reason} = SonEx.MusicBrainz.lookup(:artist, "invalid-mbid")
# Handle errors as needed

Examples

Finding an Artist's Discography

artist_mbid = "5b11f4ce-a62d-471e-81fc-a69a8278c7da" # Nirvana

# Get artist info
{:ok, artist} = SonEx.MusicBrainz.lookup(:artist, artist_mbid)
IO.puts("Artist: #{artist["name"]}")

# Browse all official albums
{:ok, result} = SonEx.MusicBrainz.browse(
  :release_group,
  [artist: artist_mbid],
  type: "album",
  limit: 100
)

Enum.each(result["release-groups"], fn rg ->
  IO.puts("  #{rg["title"]} (#{rg["first-release-date"]})")
end)

Searching for Recordings by ISRC

isrc = "USCA29900012"

{:ok, result} = SonEx.MusicBrainz.search(:recording, "isrc:#{isrc}")

case result["recordings"] do
  [recording | _] ->
    IO.puts("Found: #{recording["title"]}")
    IO.puts("Artist: #{get_in(recording, ["artist-credit", 0, "name"])}")
  [] ->
    IO.puts("No recording found for ISRC: #{isrc}")
end

Getting Label Catalog

label_mbid = "label-mbid-here"

# Get all releases from a label
{:ok, label_info} = SonEx.MusicBrainz.lookup(:label, label_mbid)

{:ok, releases} = SonEx.MusicBrainz.browse(
  :release,
  [label: label_mbid],
  limit: 100,
  inc: ["artists", "release-groups"]
)

IO.puts("Label: #{label_info["name"]}")
IO.puts("Total releases: #{releases["release-count"]}")

Working with Cover Art

The library includes support for the Cover Art Archive API, which provides cover art images for releases and release groups:

# Get cover art metadata for a release
{:ok, metadata} = SonEx.MusicBrainz.fetch_release_cover_art("release-mbid")

# Access image information
Enum.each(metadata["images"], fn image ->
  IO.puts("Image URL: #{image["image"]}")
  IO.puts("Front cover: #{image["front"]}")
  IO.puts("Types: #{inspect(image["types"])}")
  IO.puts("Thumbnails: #{inspect(Map.keys(image["thumbnails"]))}")
end)

# Get the front cover image URL
{:ok, url} = SonEx.MusicBrainz.fetch_front("release-mbid")
# => {:ok, "https://archive.org/download/mbid-770b9b80-.../image.jpg"}

# Get a thumbnail (250px, 500px, or 1200px)
{:ok, url} = SonEx.MusicBrainz.fetch_front("release-mbid", size: 500)
# => {:ok, "https://archive.org/download/mbid-770b9b80-.../image-500.jpg"}

# Get back cover
{:ok, url} = SonEx.MusicBrainz.fetch_back("release-mbid")
# => {:ok, "https://archive.org/download/mbid-770b9b80-.../back.jpg"}

# Get cover art for a release group
{:ok, metadata} = SonEx.MusicBrainz.fetch_release_group_cover_art("release-group-mbid")

# Get front cover from a release group
{:ok, url} = SonEx.MusicBrainz.fetch_front(
  "release-group-mbid",
  entity_type: :release_group
)

# Get specific image by ID
{:ok, url} = SonEx.MusicBrainz.fetch_cover_art_image(
  "release-mbid",
  "1234567890",
  size: 250
)

Available cover art functions:

Thumbnail sizes:250, 500, 1200 (pixels)

Response Format:

Rate Limiting

MusicBrainz enforces rate limits (approximately 1 request per second for anonymous users). This client does not implement rate limiting internally.

For production applications, you should implement rate limiting at a higher level (e.g., using a GenServer-based queue, a library like ex_rated, or a supervision tree managing backpressure).

Testing

The library includes comprehensive tests using mock-based testing (no real API calls):

# Run tests
mix test

# Run tests with coverage
mix test --cover

API Documentation

For detailed API documentation, see:

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Please ensure:

Changelog

v0.2.1 (2025-10-25)

Added:

v0.2.0 (2025-10-24)

Added:

Changed:

v0.1.0 (Initial Release)

Added:

License

This project is licensed under the MIT License - see the LICENSE file for details.

Resources