Skip to main content

bandcamp-explorer

A terminal browser and Python library for Bandcamp.

Search for artists and albums, discover releases by genre and location, browse artist/label profiles and discographies, all from the command line.

Install

Requires Python 3.12+.

Terminal CLI

uv tool install bandcamp-explorer
# or
pip install bandcamp-explorer

Discord bot

uv tool install bandcamp-explorer[discord]
# or
pip install bandcamp-explorer[discord]

Create a bot application at the Discord Developer Portal, enable the bot scope with Send Messages and Use Slash Commands permissions, then invite it to your server with the generated OAuth2 URL.

Set your bot token and run:

export DISCORD_TOKEN=your-bot-token
bandcamp-discord
# or with a .env file in the current directory
bandcamp-discord

Use --guild GUILD_ID to sync slash commands instantly to a specific server (global sync can take up to an hour).

Slash commands (all under /bandcamp):

Command Description
/bandcamp search <query> Search everything
/bandcamp album <query> Search albums
/bandcamp artist <query> Search artists/labels
/bandcamp track <query> Search tracks
/bandcamp discover <tag> Browse releases by tag (with optional slice and location filters)

Development

git clone https://github.com/gabriel-jung/bandcamp-explorer.git
cd bandcamp-explorer
uv sync

CLI

bandcamp "caladan brood"                  # search everything
bandcamp "erang" --artist                 # artists/labels only
bandcamp "echoes of battle" --album       # albums only
bandcamp "a forest whisper" --track       # tracks only

Browse by tag

bandcamp --tag dungeon-synth                        # newest arrivals (default)
bandcamp --tag black-metal --top                    # best-selling
bandcamp --tag dungeon-synth --rand                 # surprise me
bandcamp --tag dungeon-synth --location france
bandcamp --tag dungeon-synth --location paris
bandcamp --tag dungeon-synth black-metal            # multi-tag

Slices: --new (default), --top, --rand.

Locations are resolved to geoname IDs via Bandcamp's autocomplete and cached locally; force a refresh with --refresh-location.

Direct URLs

bandcamp https://erang.bandcamp.com/album/tome-iv
bandcamp https://erang.bandcamp.com

Interactive navigation

After selecting a result, you enter an interactive browser:

  • Artists: view bio, browse discography, select an album to see its tracklist, select a track to view its page, navigate to the label.
  • Albums: header with tracklist, description, and lyrics; navigate to the artist/host page or select a track.

Press 0 to go back, Ctrl+C to quit.

Output modes

bandcamp "erang" --artist --json            # output as JSON
bandcamp "erang" --limit 10                 # cap results
bandcamp --tag dungeon-synth --json --limit 100   # cap tag dump
bandcamp https://erang.bandcamp.com/album/tome-iv --json
bandcamp https://erang.bandcamp.com/album/tome-iv --full   # all sections at once
bandcamp -v ...                             # enable debug logging

Terminal images

Album covers and artist images render inline on terminals that support the iTerm2 or Kitty image protocol (iTerm2, Kitty, WezTerm, Mintty).

Library

The core module has no terminal dependencies; use it in scripts, bots, or other tools. All data is returned as plain dicts with a _type discriminator key.

from bandcamp_explorer.core import (
    BandcampClient, AlbumAPI, ArtistAPI, DiscoverWebAPI, SearchAPI,
    NotFoundError, resolve_geoname,
)

with BandcampClient() as client:
    # Search (one call returns the whole result set)
    results = SearchAPI(client).search("caladan brood", item_type="album")

    # Discover releases by tag
    discover = DiscoverWebAPI(client)
    releases, cursor, total = discover.discover(tags=["dungeon-synth"], slice_="new")
    all_releases = discover.discover_all(tags=["dungeon-synth"], max_pages=3)

    # Fetch album details (skip cover-art bytes with fetch_art=False)
    album = AlbumAPI(client).get("https://erang.bandcamp.com/album/tome-iv")
    for track in album["tracks"]:
        print(f"  {track['position']}. {track['title']} ({track['duration']})")

    # Fetch artist/label profile
    artist = ArtistAPI(client).get("https://erang.bandcamp.com")
    for item in artist["discography"]:
        print(f"  {item['title']}")

    # Location filtering (geoname-based)
    geoname_id = resolve_geoname(client, "paris")
    releases, _, _ = discover.discover(tags=["dungeon-synth"], geoname_id=geoname_id)

    # Download images
    client.download_image(album.get("image_url"), output_dir="./images/")

Errors

AlbumAPI.get and ArtistAPI.get raise NotFoundError when a page 404s, so callers can tell a deleted release from a failed fetch. Every other transport failure returns None. If Bandcamp answers with its bot-defence interstitial, the client raises ChallengeError and then fails fast for two minutes, raising the subclass ChallengeBackoffError without touching the network. Never treat a ChallengeError as a missing resource; it means "ask again later".

from bandcamp_explorer.core import ChallengeError, NotFoundError

try:
    album = AlbumAPI(client).get(url)
except NotFoundError:
    ...  # gone for good, stop retrying
except ChallengeError:
    ...  # blocked for now, retry later

A deleted artist subdomain is also reported as NotFoundError, even though its root page never answers 404.

TLS fingerprints

impersonate picks the curl_cffi fingerprint (default: the floating "chrome" alias). Worth changing if Bandcamp starts challenging it.

client = BandcampClient(impersonate="firefox144")

challenge_fallback_impersonate re-sends a challenged request on another fingerprint, and fallback_impersonate re-checks a 404 on one. Both are off by default; SUGGESTED_FALLBACK_IMPERSONATE is a starting list.

License

MIT

Metadata

Release files for bandcamp-explorer 0.8.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bandcamp-explorer 0.8.3
File Size Uploaded Provenance
bandcamp_explorer-0.8.3.tar.gz 35.0 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for bandcamp-explorer 0.8.3
File Interpreter ABI Platform
bandcamp_explorer-0.8.3-py3-none-any.whl Python 3 none any Details

Total release size: 77.2 kB

Release files / bandcamp_explorer-0.8.3.tar.gz

Download URL bandcamp_explorer-0.8.3.tar.gz
Size 35.0 kB
Tags Source
SHA-256 checksum
How to use checksums
64f0a4eb1dd110ceeccd44f5f415f7b9f40e4465b43c2f35c99c0b6729fd046d
BLAKE2b-256 checksum
How to use checksums
2514bac4b7152016bd51f37f8409902d65f208ded63f9dc0efdcad7c047ff2fe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release files / bandcamp_explorer-0.8.3-py3-none-any.whl

Download URL bandcamp_explorer-0.8.3-py3-none-any.whl
Size 42.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d7579f1585ce9e3a3aaa965d0c988410ef1991ea4b139633fe4d0982166f2c6a
BLAKE2b-256 checksum
How to use checksums
14c6a0674ba6d55e45d0990309dfc85671e5f7655017c007998f3abfc47cfaae
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Security for bandcamp-explorer 0.8.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for bandcamp_explorer-0.8.3.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page