CLI tool
Evolution0/bandcamp-dl avatar
Evolution0/bandcamp-dl

bandcamp-dl: a command line downloader for Bandcamp albums

Simple python script to download Bandcamp albums

1,182 stars116 forksPythonUnlicense

At a glance

What is it?
bandcamp-dl is a small Python command line app that downloads albums and tracks from bandcamp.com, with a filename template system, Unicode-aware slugification, embedded art and lyrics, and the option to pull a whole artist discography. It is released into the public domain under the Unlicense.
Who is it for?
Adopt bandcamp-dl if you want to archive albums that Bandcamp offers as free downloads, or to pull your own purchased material into a local library in a predictable layout. Do not adopt it to obtain paid albums, since the tool does not add any access the platform does not grant.
Can I use it commercially?
Yes. Unlicense is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 14 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A small script with a real option surface

bandcamp-dl is described as a small command-line app to download audio from bandcamp.com. It requires the Python interpreter, version 3.4 or higher according to its own description, and it is not platform specific. The synopsis is a single command with a URL argument, and the usage line is:

code
bandcamp-dl [options] [URL]

The tool has grown well past the shape of a script. The option list in the project documentation covers downloading a whole artist discography by artist slug, a single track or album by slug, choosing the output filename template, a base directory for all downloads, requiring that every track of an album be available before downloading it, overwriting existing files, skipping album art, embedding lyrics, using the album or track label as iTunes grouping, embedding album art, setting cover art quality, disabling slugification, restricting the allowed characters in slugification, choosing the replacement character for spaces, restricting output to ASCII, keeping whitespace in filenames, converting case, skipping confirmation prompts, embedding genres, and truncating album and track titles to a maximum length.

That is a substantial command line interface, and most of it exists to solve the problem that matters when you are building a local library: deciding what the files are called and where they go.

The project is on PyPI as bandcamp-downloader, with the console script named bandcamp-dl. It is licensed under the Unlicense, which the documentation describes as releasing it to the public domain, so you can modify it, redistribute it, or use it however you like. The two authors listed in the package metadata are Iheanyi Ekechukwu and Anthony Forsberg, and the current development version in the metadata is 1.0.0.dev1 with a Python requirement of 3.13 or newer.

The filename template system

The option that does the most work is --template, which lets you describe the output file names and directories with tokens in the %{token} format. The allowed tokens are trackartist for the artist name, artist for the album artist name, album for the album name, track for the track number, title for the track title, date for the album date, and label for the album label. The default template is:

code
%{artist}/%{album}/%{track} - %{title}

That default is a sensible library layout, since it produces an artist directory, an album directory inside it, and a file named by track number and title. The tokens are also usable in combinations that the default does not use, so a flat layout with the date in the name is a matter of writing a different string rather than moving files afterwards.

Two details interact with the template in a way that is easy to miss. The trackartist token and the artist token are not the same thing, because one is the track's artist and one is the album's, and for a compilation they differ. And the date and label tokens come from the album metadata, so they are empty on releases where the platform does not expose that data.

The truncation options fit in the same family. --truncate-album takes a length, --truncate-track takes a length, and 0 means no limit, which is the way to keep a long album title intact when a filesystem would otherwise cut it at 255 characters.

Slugification, and the options that undo it

Bandcamp slugs are lower-case and hyphenated, which is not what most music libraries want, so the tool slugifies by default and gives you several ways to control or disable that.

-y, --no-slugify turns slugification off entirely, which is the option to reach for if your library is already organised and you want the original capitalisation preserved. -c, --ok-chars specifies the allowed characters in slugification, with a default of -_~, and -s, --space-char specifies the character used in place of spaces, with a default of -. -a, --ascii-only restricts output to ASCII characters, and the documentation gives the example 北京 becomes bei-jing-capital-of-china, which shows the transliteration step rather than a stripping one. -k, --keep-spaces retains whitespace in filenames, and -x, --case-convert takes lower, upper, camel, or none, with lower as the default.

The interesting part is that these compose rather than conflict. You could keep spaces, keep the original case with --case-convert none, and restrict the character set, and each of those is a separate decision. That is a well-designed option set for a tool whose output is consumed by other software, since the filename is an interface.

One option deserves a separate note because it changes the download itself rather than the naming. -f, --full-album downloads only if all tracks are available, which is the flag to use when you want a complete album or nothing rather than a partial one. The -n, --no-art flag skips grabbing album art, and -r, --embed-art embeds it when it is available, with --cover-quality setting the resolution: 0 for source, 10 for the album page at 1200x1200, and 16 as the default embed at 700x700.

Dependencies, and how the parsing is done

The dependency list is short and tells you the shape of the implementation. The package metadata lists beautifulsoup4 at 4.15.0 or higher for HTML parsing, demjson3 at 3.0.6 or higher for converting JavaScript dictionaries to JSON, mutagen at 1.48.1 or higher, requests at 2.34.2 or higher, urllib3 at 2.8.0 or higher, and requests-ratelimiter at 0.10.0 or higher. The Unicode slugification comes from unicode-slugify, installed from a specific pull request in the mozilla repository rather than from PyPI, which is unusual and worth knowing about before you depend on the build.

The stack is coherent. Bandcamp pages carry the track listing as HTML, so BeautifulSoup handles that. The audio URLs and the structured data embedded in the page are in a JavaScript object literal, which is what demjson is for, since Bandcamp does not serve a clean JSON API for that part. Mutagen handles the ID3 and other tag writing that the embed options require, which is why embedding lyrics, genres, art, and the iTunes grouping all work on the output files. And requests-ratelimiter is the polite layer that keeps the tool from hammering the site.

That last point is a design decision rather than an afterthought. A downloader that runs at full speed against a small platform is both rude and a good way to get your requests blocked, and rate limiting is the difference between a tool that keeps working and one that starts failing with errors that look like site breakage.

The command line itself is built with argparse, judging by the option formatting in the usage block, with the standard help, version, and debug flags at the top.

Installing it in four different ways

The project supports five installation routes, which is unusual for a tool of this size and reflects how differently people arrive at it.

From PyPI:

code
pip3 install bandcamp-downloader

The documentation notes that some Linux distributions may require python3-pip to be installed first. From a wheel, you download the.whl file from PyPI or the Releases page, cd into the directory containing it, and run pip install with the filename. On macOS there is a Homebrew route with brew install bandcamp-dl, and on Arch there is an AUR route with yay -S bandcamp-dl-git.

And from source, you clone the project or download and extract the zip, cd into the project directory, and run pip install..

The five routes differ in what you get. The PyPI and Homebrew routes give you a released version, the wheel route lets you pin a specific artifact, the AUR route tracks the Git repository, and the source route gives you the working tree. For a tool whose output is a music library that you will keep, the choice matters less than it would elsewhere, because the version only changes which pages it knows how to parse.

The test extras are pytest and responses, with responses being a library for mocking HTTP responses, which is the right tool for testing a scraper without touching the live site. The repository is laid out with the package in a bandcamp_dl directory, a pyproject.toml, a README.rst, an AUTHORS.rst, a CHANGELOG.rst, and an UNLICENSE file.

The release gap, and the one thing to check before running it

The published release history is where caution belongs. The most recent tagged release is v0.0.17 from 2025-03-31, preceded by v0.0.16 in September 2024 and v0.0.13 in May 2022. The last push to the repository was on 2026-10-09, so the working tree is being maintained, but the version numbers tell you the project has never left the zero series.

That matters more than it would for most tools, because a scraper breaks when the site changes and the fix has to be released before you can use it. The package metadata's development version of 1.0.0.dev1 is a sign the project is preparing a proper release, and if you want the current fixes you would install from the repository rather than from PyPI.

The one thing to check before running it is the confirmation prompt behaviour. The --no-confirm option overrides confirmation prompts, and the documentation itself marks it with a caution. The prompts are the mechanism that stops a mistyped artist slug from downloading an entire discography you did not want, and a tool that fetches hundreds of files on a single command deserves that check.

The bug reporting guidance in the project documentation is unusually detailed, and one of its points is worth repeating for any user: the documentation says that about 20% of the reports it receives are already fixed, because people are using outdated versions. That is a useful signal about how the project is maintained and about how much of the friction you would hit is version-related.

Editorial conclusion

Adopt bandcamp-dl if you want to archive albums that Bandcamp offers as free downloads, or to pull your own purchased material into a local library in a predictable layout. Do not adopt it to obtain paid albums, since the tool does not add any access the platform does not grant. Verify first the filename template and slug options against your filesystem conventions, because the defaults lower-case names and replace spaces with hyphens, which is not what most music libraries want.

Frequently asked questions

How do I install bandcamp-dl?

From PyPI with pip3 install bandcamp-downloader, or from a wheel by downloading the .whl file and running pip install with its filename, or with brew install bandcamp-dl on macOS, yay -S bandcamp-dl-git on Arch, or pip install . from a cloned source directory. The package requires Python 3.13 or newer per the current metadata.

How do I change the output filenames in bandcamp-dl?

Use the --template option, whose tokens are trackartist, artist, album, track, title, date, and label, formatted as %{token}. The default template is %{artist}/%{album}/%{track} - %{title}. You can also disable slugification with --no-slugify and control case with --case-convert.

What does the --full-album flag do?

It downloads only if all tracks are available, so you get a complete album or nothing rather than a partial download. The opposite case is covered by the default behaviour, which downloads the tracks it can find.

Which license is bandcamp-dl released under?

The Unlicense, which the project documentation describes as releasing it to the public domain, so you can modify it, redistribute it, or use it however you like. The repository carries an UNLICENSE file and the package metadata declares license = {text = "Unlicense"}.

How does bandcamp-dl find the audio files?

The dependencies explain the approach: BeautifulSoup parses the HTML of the album page for the track listing, and demjson converts the JavaScript dictionary embedded in that page into JSON, since Bandcamp does not expose a clean JSON API for the audio URLs. Mutagen then writes the tags for the embedded lyrics, genres, and art options.

Official sources

  1. Evolution0/bandcamp-dl on GitHub
  2. Issues
  3. License: Unlicense
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/evolution0-bandcamp-dl.svg)](https://hysenlabs.com/projects/evolution0-bandcamp-dl)

Was this useful?