Skip to main content

Bandcamp Async API

Project description

Stand With Ukraine Made in Ukraine Stand With Ukraine Russian Warship Go Fuck Yourself

Bandcamp Async API

A modern, asynchronous Python client for the Bandcamp API.

This project was created to implement a Bandcamp music provider for Music Assistant, enabling seamless integration of Bandcamp's music catalog into home audio systems.

Features

  • Search: Search for artists, albums, and tracks across Bandcamp
  • Albums: Retrieve detailed album information including track listings
  • Tracks: Get individual track details and streaming information
  • Artists: Access artist profiles, discographies, and metadata
  • Collections: Browse user collections and wishlists (auth required for private data)
  • Following: Access following bands, following fans, and followers
  • Feed: Get personalized music feed with new releases from followed artists
  • Async: Fully asynchronous API using aiohttp
  • Type-safe: Complete type hints for all models and methods
  • Well-tested: Comprehensive test suite with real API data

Installation

Install from PyPI:

pip install bandcamp-async-api

Or using uv:

uv add bandcamp-async-api

Quick Start

import asyncio
from bandcamp_async_api import BandcampAPIClient

async def main():
    async with BandcampAPIClient(identity_token='7%09optional_identity_token%7D') as client:
        # Search for music
        results = await client.search("radiohead")
        print(f"Found {len(results)} results")

        # Get album details
        if results:
            album_result = next(r for r in results if r.type == "album")
            album = await client.get_album(album_result.artist_id, album_result.id)
            print(f"Album: {album.title} by {album.artist.name}")

        # Get artist information
        artist_result = next(r for r in results if r.type == "artist")
        artist = await client.get_artist(artist_result.id)
        print(f"Artist: {artist.name} - {artist.bio}")

if __name__ == '__main__':
    asyncio.run(main())

Authentication

For accessing user collections, you need to obtain an identity token from Bandcamp cookies:

from bandcamp_async_api import BandcampAPIClient

client = BandcampAPIClient(identity_token="your_identity_token")

Music Feed

The get_feed() method retrieves a personalized music feed containing new releases from followed artists, fan purchases, and fan picks. This endpoint requires authentication - you must provide an identity token.

import asyncio
from bandcamp_async_api import BandcampAPIClient, BandcampMustBeLoggedInError

async def main():
    async with BandcampAPIClient(identity_token='your_identity_token') as client:
        # Get your music feed
        feed = await client.get_feed()
        print(f"New stories: {len(feed.stories)}")
        print(f"Has more: {feed.has_more}")

        # Iterate through feed stories
        for story in feed.stories:
            print(f"  - {story.story_type}: {story.item_title} by {story.band_name}")

        # Access tracks with streaming URLs
        for track in feed.track_list:
            print(f"  Track: {track.title} - {track.streaming_url}")

        # Paginate through older stories
        if feed.has_more and feed.oldest_story_date:
            older_feed = await client.get_feed(older_than=feed.oldest_story_date)
            print(f"Older stories: {len(older_feed.stories)}")

if __name__ == '__main__':
    asyncio.run(main())

Feed Story Types

The feed contains different story types:

  • np - New track/track release
  • nr - New album release
  • p - Fan purchase
  • fp - Fan pick

Error Handling

The feed endpoint requires authentication. If you try to access it without an identity token, you'll receive a BandcampMustBeLoggedInError:

from bandcamp_async_api import BandcampAPIClient, BandcampMustBeLoggedInError

async def safe_get_feed():
    client = BandcampAPIClient()  # No identity token
    try:
        feed = await client.get_feed()
    except BandcampMustBeLoggedInError:
        print("Feed requires authentication - provide an identity token")

API Reference

Core Client

  • BandcampAPIClient() - Main API client
  • search(query: str) - Search Bandcamp
  • get_album(artist_id, album_id) - Get album details
  • get_track(artist_id, track_id) - Get track details
  • get_artist(artist_id) - Get artist details
  • get_collection_summary() - Get collection overview
  • get_collection_items(collection_type, older_than_token, count, fan_id) - Get collection/wishlist/following items with pagination
  • get_artist_discography(artist_id) - Get artist's complete discography
  • get_feed(older_than) - Get personalized music feed with pagination support

Data Models

  • SearchResultItem - Base search result
  • BCAlbum - Album with tracks and metadata
  • BCTrack - Individual track information
  • BCArtist - Artist/band profile
  • CollectionSummary - User's collection data
  • CollectionItem - Individual collection item
  • FollowingItem - Band/artist from following list
  • FanItem - Fan/user from following_fans or followers
  • FeedResponse - User's music feed with stories and tracks
  • FeedStory - Individual feed story (new release, fan purchase, etc.)
  • FeedTrack - Track from feed with streaming URL
  • FeedBandInfo - Band information referenced in feed
  • FeedFanInfo - Fan information referenced in feed

Exceptions

  • BandcampAPIError - Base API error
  • BandcampNotFoundError - Resource not found
  • BandcampBadQueryError - Invalid search query
  • BandcampRateLimitError - Rate limit exceeded (includes retry_after attribute)

Error Handling

The client provides specific exception types for different error conditions:

from bandcamp_async_api import (
    BandcampAPIClient,
    BandcampNotFoundError,
    BandcampAPIError
)

async def safe_get_album(client, artist_id, album_id):
    try:
        return await client.get_album(artist_id, album_id)
    except BandcampNotFoundError:
        print("Album not found")
        return None
    except BandcampAPIError as e:
        print(f"API error: {e}")
        return None

Rate Limiting

When Bandcamp's API rate limit is exceeded, a BandcampRateLimitError is raised with a retry_after attribute indicating how many seconds to wait before retrying:

import asyncio
from bandcamp_async_api import BandcampAPIClient, BandcampRateLimitError

async def get_album_with_retry(client, artist_id, album_id, max_retries=3):
    for attempt in range(max_retries):
        try:
            return await client.get_album(artist_id, album_id)
        except BandcampRateLimitError as e:
            if attempt < max_retries - 1:
                wait_time = e.retry_after or 30
                print(f"Rate limited. Waiting {wait_time} seconds...")
                await asyncio.sleep(wait_time)
            else:
                raise

For automatic retries with exponential backoff, you can use the tenacity library:

from tenacity import retry, retry_if_exception_type, wait_exponential
from bandcamp_async_api import BandcampAPIClient, BandcampRateLimitError

@retry(
    retry=retry_if_exception_type(BandcampRateLimitError),
    wait=wait_exponential(multiplier=1, min=30, max=300)
)
async def get_album(client, artist_id, album_id):
    return await client.get_album(artist_id, album_id)

Development

Setup

# Clone the repository
git clone https://github.com/ALERTua/bandcamp_async_api.git
cd bandcamp_async_api

# Install dependencies
uv sync --dev

# Run tests
uv run pytest

# Run linting
uv run ruff check

Testing

The project includes comprehensive tests:

# Run all tests
uv run pytest

# Run integration tests (requires real API access)
echo "BANDCAMP_IDENTITY_TOKEN=7%09identity_token%7D" > .env
uv run pytest tests/real_data/

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass
  5. Submit a pull request

This project is built based on data from:

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

bandcamp_async_api-0.1.0.tar.gz (13.0 kB view details)

Uploaded Source

Built Distribution

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

bandcamp_async_api-0.1.0-py3-none-any.whl (18.7 kB view details)

Uploaded Python 3

File details

Details for the file bandcamp_async_api-0.1.0.tar.gz.

File metadata

  • Download URL: bandcamp_async_api-0.1.0.tar.gz
  • Upload date:
  • Size: 13.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for bandcamp_async_api-0.1.0.tar.gz
Algorithm Hash digest
SHA256 0e0d7345be06843b7b05aaf3009a556481f1a9f79f54e4e79ea43fd56881006b
MD5 5db971cd5ca8b0a5a103a75f90b504ac
BLAKE2b-256 388db3321a916d9856d3c4234b4531288a49426691f59bef0e4a7a188da1a98c

See more details on using hashes here.

File details

Details for the file bandcamp_async_api-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: bandcamp_async_api-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 18.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for bandcamp_async_api-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7997a2b6c1803aba313258d34b78a162cc4f81f1807ea0fa67d1c5e32f0e8d4e
MD5 26d8f451632ef3c6570edbcfe0c96e6b
BLAKE2b-256 041b1564ff90d9be67863cc7c275cc29d4dd3f5cd79c0d071092a53077c9da8a

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