Skip to main content

metal-archives.com Python client with a relational data model

Project description

pymetal

A Python client for Encyclopaedia Metallum (the Metal Archives) with a relational data model that captures what flat scrapers lose: splits, lineups changing 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 collapses three independent facts MA keeps separate:

  • a track may have multiple bands (split releases, collaborations);
  • a band's lineup is time-sliced — "the same band" on two tracks may mean different humans;
  • a track may appear on many releases (compilations, re-issues, singles).

pymetal models each as a first-class entity (TrackAppearance, LineupMember, ReleaseLineup) keyed by metal-archives ids so re-scrapes are idempotent.

Install

pip install -e .

Requires Python 3.10+. Pulls curl_cffi, lxml, pydantic>=2, 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 in examples/:

Endpoints

Search (advanced-search forms)

Function What it returns
search_bands(...) Iterator[BandSearchHit] — every advanced filter (country, status, year range, themes, location, label)
search_albums(...) Iterator[AlbumSearchHit] — release type, format, label, catalog/barcode, year+month range
search_songs(...) Iterator[SongSearchHit] — full-text lyrics search; carries band_id / release_id / 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 per-band
get_release_lineup(id) List[ReleaseLineup] — band / guest / 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/merch grouped by section
get_lyrics_by_song_id(id) Optional[str]
get_lyrics(...) Iterator[str] — combined search + lyrics fetch

Catalog browse + discovery

Function What it returns
browse_bands_by_country(code) Iterator[BandSearchHit] — full country listing
browse_bands_by_genre(slug) Iterator[BandSearchHit] — 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 return Pydantic v2 models — .model_dump_json() round-trip works on every type.

Documentation

License

Apache 2.0

Project details


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.0.1a1.tar.gz (40.0 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.0.1a1-py3-none-any.whl (33.6 kB view details)

Uploaded Python 3

File details

Details for the file pymetal-1.0.1a1.tar.gz.

File metadata

  • Download URL: pymetal-1.0.1a1.tar.gz
  • Upload date:
  • Size: 40.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pymetal-1.0.1a1.tar.gz
Algorithm Hash digest
SHA256 941923b5257ab9d74a645dfbcc502b83f7274218ddc48460441d19a2ad26b772
MD5 4d491e7d81314e98ed5811762ee095c4
BLAKE2b-256 3d27314cbdf887ba7221883e475d3575967274fcbf1f060a97f5b36a9ef0774a

See more details on using hashes here.

File details

Details for the file pymetal-1.0.1a1-py3-none-any.whl.

File metadata

  • Download URL: pymetal-1.0.1a1-py3-none-any.whl
  • Upload date:
  • Size: 33.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pymetal-1.0.1a1-py3-none-any.whl
Algorithm Hash digest
SHA256 0210cd9021a0b7fc56176aec1427239d797b705e593b82b0ca5a080874ef9490
MD5 b7a85c6f40fe98083b507d30111fd58d
BLAKE2b-256 e1b1d6d3ed70241b282a5fe0b5a450081a1374b3929b582158dc75b6f8076ae4

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 Pingdom Monitoring Sentry Error logging StatusPage Status page