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.1.tar.gz (39.9 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.1-py3-none-any.whl (33.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pymetal-1.0.1.tar.gz
  • Upload date:
  • Size: 39.9 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.1.tar.gz
Algorithm Hash digest
SHA256 7e91bda32bed76b96530db77092b03e45ca01bdd802e32bd87893089ba81fc31
MD5 8f4ddd7e52b2ee8862cf2bc45e494420
BLAKE2b-256 83522b86af6f592c3110396de7bb84312ec53bcc87825e59b690df9349092be1

See more details on using hashes here.

File details

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

File metadata

  • Download URL: pymetal-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 33.5 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 69d13fa0f0bda3756c46f7684cef3dbda68ffcffc380f80d98d9bf6710950e2a
MD5 5b6f7ed3607d28280832d3430f0831b0
BLAKE2b-256 f8d8303cc1331dbfd8ec2e2389d3c616aeb766152a96e6a8ba12d4c2a1fdc6af

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