Skip to content

Instantly share code, notes, and snippets.

@Romern
Last active January 15, 2022 18:44
Show Gist options
  • Save Romern/cd7f1e9a742d27eb3ac104201f6ae87c to your computer and use it in GitHub Desktop.
Save Romern/cd7f1e9a742d27eb3ac104201f6ae87c to your computer and use it in GitHub Desktop.
import requests
import json
import sys
import os
headers = {
'X-Requested-With': 'com.bandcamp.android',
'Content-Type': 'application/json',
'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 9; Unknown Device)',
'Host': 'bandcamp.com',
}
def get_session_cookie(session):
data = {"platform":"a","version":191577}
return session.post('https://bandcamp.com/api/mobile/24/bootstrap_data', headers=headers, json=data)
def fuzzysearch(session, query):
params = {
"q": query,
"param_with_locations": True
}
return requests.get('https://bandcamp.com/api/fuzzysearch/1/app_autocomplete', headers=headers, params=params)
# -fuzzysearch(session, query).json()["results"][0]["id"]
def get_discography(session, band_id):
data = {"band_id": str(band_id)}
return session.post('https://bandcamp.com/api/mobile/24/band_details', headers=headers, json=data)
# get_discography(session, "XXXXX").json()["discography"][0]["item_id"]
def buy_for_nothing(session, item_id, item_type="album"):
data = {"item_id": item_id, "item_type": item_type}
return session.post('https://bandcamp.com/api/mobile/24/buy_for_nothing', headers=headers, json=data)
# buy_album_for_nothing(session, "XXXXX").json()["downloads"]["flac"]["url"]
# if url is not in dict, then it is not buyable for nothing
def download_low_quality_stream(session, band_id, item_id, item_type="a"):
params = {
'band_id': str(band_id),
'tralbum_type': item_type,
'tralbum_id': str(item_id),
}
return requests.get('https://bandcamp.com/api/mobile/24/tralbum_details', headers=headers, params=params)
# download_low_quality_stream(session, XXXX, XXXXXX).json()["tracks"][0]["streaming_url"]["mp3-128"]
def download_file(session, url, filename):
with session.get(url, stream=True) as r:
r.raise_for_status()
with open(filename, 'wb') as f:
for chunk in r.iter_content(chunk_size=8192):
# If you have chunk encoded response uncomment if
# and set chunk_size parameter to None.
#if chunk:
f.write(chunk)
def download_discography(session, bandname, basedir="./"):
band_id = fuzzysearch(session, bandname).json()["results"][0]["id"]
discography = get_discography(session, band_id)
for item in discography.json()["discography"]:
item_id = item["item_id"]
item_type = item["item_type"]
url = buy_for_nothing(session, item["item_id"], item["item_type"]).json()["downloads"].get("flac")
if not url:
print(f'FLAC not available for item {item["band_name"]} - {item["title"]} ({item["item_type"]})')
continue
url = url.get("url")
base_album_dir = os.path.join(basedir, item["band_name"], item["title"])
os.makedirs(base_album_dir, exist_ok=True)
if not url:
print(f'Free (high quality) download not available for item {item["band_name"]} - {item["title"]} ({item["item_type"]}), downloading LQ version.')
lq = download_low_quality_stream(session, item["band_id"], item["item_id"], item_type="t" if item["item_type"]=="track" else "a").json()["tracks"]
# download all tracks
for track in lq:
outfilename = os.path.join(base_album_dir, f'{track["track_num"]}. {track["title"]}.mp3')
#./[outfolder]/[bandname]/[albumname]/[tracknumber]. [trackname].flac
print(f'Downloading Track {outfilename}...')
download_file(session, track["streaming_url"]["mp3-128"], outfilename)
else:
# download url
outfilename = os.path.join(base_album_dir, 'album.zip')
print(f'Downloading Track {outfilename}...')
download_file(session, url, outfilename)
if __name__ == '__main__':
if len(sys.argv)<=2:
print(f"{sys.argv[0]} [bandname] [outfolder]\nDownloads the whole discography of a band on bandcamp in FLAC if available.\nFormat: ./[outfolder]/[bandname]/[albumname]/[tracknumber]. [trackname].flac")
exit(0)
session = requests.Session()
download_discography(session, sys.argv[1], sys.argv[2])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment