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.0a2.tar.gz (39.7 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.0a2-py3-none-any.whl (33.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pymetal-1.0.0a2.tar.gz
  • Upload date:
  • Size: 39.7 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.0a2.tar.gz
Algorithm Hash digest
SHA256 1d2cb4a8ded79bad48a019028e6413d4ca356dcb3759f005e3c6f80028fdc564
MD5 cf47cc5e80158395a618d97eee852f69
BLAKE2b-256 7f6154c8f738837ba5ed627271ab331b2e0f515d9a443173a69d4f6aa81127fb

See more details on using hashes here.

File details

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

File metadata

  • Download URL: pymetal-1.0.0a2-py3-none-any.whl
  • Upload date:
  • Size: 33.4 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.0a2-py3-none-any.whl
Algorithm Hash digest
SHA256 f879da80106a8040cd52f07f95d7da346efc1db6d4bfc6a4a193c98e86d5e135
MD5 2cf7e3e69e242173df345dc3879ed9c0
BLAKE2b-256 8365729f79b1367c321bfee27491de957133be6a29593e2a33388755b6c508ad

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