Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

pymetal

A Python client for Encyclopaedia Metallum (the Metal Archives). It uses a relational data model that keeps facts flat scrapers usually lose: splits, lineups that change over time, and tracks reused across releases.

Built on curl_cffi for TLS-fingerprint bypass and pydantic for typed, validated data.

Why

Most scrapers model Track = (id, title, band, album). That model collapses three facts that MA keeps separate.

  • A track can have multiple bands (split releases, collaborations).
  • A band's lineup is time-sliced. The same band on two tracks can mean different people.
  • A track can appear on many releases (compilations, re-issues, singles).

pymetal models each fact as a separate entity (TrackAppearance, LineupMember, ReleaseLineup), keyed by metal-archives ids. This keeps re-scrapes idempotent.

Install

pip install -e .

Requires Python 3.10+. Pulls in curl_cffi, lxml, pydantic>=2, and random-user-agent.

Quick start

from pymetal import MetalArchives

ma = MetalArchives()

# Search bands with the full advanced-search filter set.
for hit in ma.search_bands(country="PT", genre="Heavy", year_from=1980, year_to=1989):
    print(hit.ma_id, hit.name, hit.country)

# Pull a release with all its tracks (per-band attribution on splits).
release, songs, appearances = ma.get_release(451600)  # Carcass — Heartwork
print(release.cover_url, release.total_length, release.label_name)
print(release.reviews_count, "reviews", release.reviews_avg_percent, "% avg")

# Lineup over time — Current / Past / Live / Last-known / Guest-Session.
for member in ma.get_lineup(14):
    print(member.status, member.artist_name, member.role, member.date_from, member.date_to)

# Lyrics by song id.
print(ma.get_lyrics_by_song_id(172090))

More examples are in examples/:

Endpoints

Search (advanced-search forms)

Function What it returns
search_bands(...) Iterator[BandSearchHit]. Covers every advanced filter: country, status, year range, themes, location, label.
search_albums(...) Iterator[AlbumSearchHit]. Covers release type, format, label, catalog/barcode, year and month range.
search_songs(...) Iterator[SongSearchHit]. Full-text lyrics search, carries band_id, release_id, and lyrics_id.

Detail pages

Function What it returns
get_band(id) Band: name, country, genres, themes, labels, comment, photo, audit.
get_lineup(id) List[LineupMember], partitioned by status with role-date ranges.
get_release(id) (Release, List[Song], List[TrackAppearance]). Splits attribute tracks per band.
get_release_lineup(id) List[ReleaseLineup]: band, guest, and staff credits.
get_other_versions(id) List[Release]: re-issues, re-masters, regional editions.
get_discography(id) List[Release]
get_artist(id) Artist: real name, born, R.I.P., died of, place of birth.
get_label(id) Label: address, phone, styles, founding date, sub-labels, parent.
get_band_recommendations(id) List[BandRecommendation], MA's "Similar artists" tab.
get_band_reviews(id) Iterator[Review], every user review of every release by a band.
get_links(id, entity_type='band') List[ExternalLink]: Bandcamp, Spotify, and merch links grouped by section.
get_lyrics_by_song_id(id) Optional[str]
get_lyrics(...) Iterator[str], a combined search and lyrics fetch.

Catalog browse and discovery

Function What it returns
browse_bands_by_country(code) Iterator[BandSearchHit], the full country listing.
browse_bands_by_genre(slug) Iterator[BandSearchHit], from a 23-bucket coarse taxonomy.
browse_bands_by_letter(letter) Iterator[BandSearchHit], alphabetical (A-Z, NBR, ~).
browse_labels_by_country(code) Iterator[Label]
browse_labels_by_letter(letter) Iterator[Label]
browse_reviews(year, month) Iterator[Review], reviews posted in a given month.
get_upcoming_releases() Iterator[UpcomingRelease], scheduled future releases.
get_rip_artists() Iterator[RIPArtist], MA's deceased-artists list.
list_countries() dict[code, name], all MA-known country codes.
list_genre_slugs() list[str], the 23 genre browse slugs.

All functions return Pydantic v2 models. .model_dump_json() round-trips on every type.

Documentation

License

Apache 2.0

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pymetal-1.1.0a2.tar.gz (40.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pymetal-1.1.0a2-py3-none-any.whl (33.7 kB view details)

Uploaded Python 3

File details

Details for the file pymetal-1.1.0a2.tar.gz.

File metadata

  • Download URL: pymetal-1.1.0a2.tar.gz
  • Upload date:
  • Size: 40.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pymetal-1.1.0a2.tar.gz
Algorithm Hash digest
SHA256 34a6ab9111e3eb9ba12918ca7d41dc35b11cc03df05dae923bada37c9f201bd3
MD5 0940e46834b87559140fc0e0d72eb6e8
BLAKE2b-256 2fd530f9fe663107d6fc3fe860421f538b89ddc7e8702440d448358a9368217a

See more details on using hashes here.

File details

Details for the file pymetal-1.1.0a2-py3-none-any.whl.

File metadata

  • Download URL: pymetal-1.1.0a2-py3-none-any.whl
  • Upload date:
  • Size: 33.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pymetal-1.1.0a2-py3-none-any.whl
Algorithm Hash digest
SHA256 b8602627d62cc8a0fdd61b46bd2a33e39a10f1962cac7eb5733aa18a752016d5
MD5 e3c50c54ca169bef6bde4d72ef876f80
BLAKE2b-256 a4b5d7e5bf55dfc1ba5a9c1f5dbb99a3cbf71456002084aeeb0ea95ac2a9d9cc

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page