Files
vynl/backend/app/services/bandcamp.py

74 lines
2.2 KiB
Python

"""Bandcamp discovery using their public APIs (no scraping)."""
import httpx
HEADERS = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0",
}
DIG_DEEPER_URL = "https://bandcamp.com/api/hub/2/dig_deeper"
async def discover_by_tag(
tags: list[str],
sort: str = "new",
page: int = 1,
) -> list[dict]:
"""Discover new music on Bandcamp by tag using their public API.
Args:
tags: List of genre/tag strings (e.g. ["indie-rock", "shoegaze"])
sort: "new", "rec", or "pop" (new releases, recommended, popular)
page: Page number for pagination
Returns list of releases with: title, artist, art_url, bandcamp_url, genre, item_type
"""
async with httpx.AsyncClient(timeout=15, headers=HEADERS) as client:
resp = await client.post(
DIG_DEEPER_URL,
json={
"filters": {
"format": "all",
"location": 0,
"sort": sort,
"tags": tags,
},
"page": page,
},
)
if resp.status_code != 200:
return []
data = resp.json()
results = []
for item in data.get("items", []):
art_id = item.get("art_id")
art_url = f"https://f4.bcbits.com/img/a{art_id}_16.jpg" if art_id else None
tralbum_type = item.get("tralbum_type", "a")
type_path = "album" if tralbum_type == "a" else "track"
item_url = item.get("tralbum_url", "")
results.append({
"title": item.get("title", ""),
"artist": item.get("artist", ""),
"art_url": art_url,
"bandcamp_url": item_url,
"genre": ", ".join(tags),
"item_type": type_path,
})
return results
async def get_trending_tags() -> list[str]:
"""Return common Bandcamp genre tags for discovery."""
return [
"indie-rock", "electronic", "hip-hop-rap", "ambient", "punk",
"experimental", "folk", "jazz", "metal", "pop", "r-b-soul",
"shoegaze", "post-punk", "synthwave", "lo-fi", "dream-pop",
"indie-pop", "psychedelic", "garage-rock", "emo",
]