bandcamp-fetch
v3.2.1
Published
Scrape Bandcamp content
Maintainers
Readme
bandcamp-fetch
Library for scraping Bandcamp content.
Coverage:
- Bandcamp Discover
- Album and track info
- Artists, labels, label artists, discography
- Articles (aka. Bandcamp Daily)
- Shows
- Tags, including releases and highlights by tag
- Search
- Fan collections, wishlists and following artists / genres
Packaged as ESM + CJS hybrid module with typings.
Installation
npm i --save bandcamp-fetchOptional packages
The above command will install the following optional packages:
puppeteer puppeteer-extra puppeteer-extra-plugin-stealthThese packages enable automated cookie fetching, which is performed when utilizing search functions without setting a cookie.
You can skip the installation of these optional packages:
npm i --save --omit=optional bandcamp-fetchBe aware that, without at least the puppeteer package, performing searches without a cookie will result in an error.
Setting Puppeteer's executable path
When you install puppeteer, the process will automatically download a suitable browser executable to use at runtime. In case you want puppeteer to use your own browser executable, you can do so as follows:
import bcfetch from 'bandcamp-fetch';
bcfetch.setPuppeteerExecutablePath('/path/to/executable');Usage
import bcfetch from 'bandcamp-fetch';
const results = await bcfetch.discovery.discover(...);User Sessions
When you visit Bandcamp, a "Cookie" is used to identify the user session. If you are signed in, you can pass the value of this cookie to the library and gain access to your private collection as well as high-quality MP3 streams of purchased media:
bcfetch.setCookie('xxxx');
const album = await bcfetch.album.getInfo({
albumUrl: '...' // URL of purchased album
});
// Normal quality stream
const streamUrl = album.tracks[0].streamUrl;
// High quality stream - only available when `cookie` is set
const streamUrlHQ = album.tracks[0].streamUrlHQ;Guide: How to obtain Cookie
BandcampFetch
The library exports a default BandcampFetch instance mainly for backward compatibility with previous versions:
// Imports the default `BandcampFetch` instance
import bcfetch from 'bandcamp-fetch';You can also create separate instances. This is useful when you want to support multiple user sessions:
import { BandcampFetch } from 'bandcamp-fetch';
const bcfetch1 = new BandcampFetch({
cookie: 'xxxx' // Cookie for user session 1
});
const bcfetch2 = new BandcampFetch();
bcfetch2.setCookie('yyyy'); // Cookie for user sesion 2API
Discovery API
To access the Discovery API:
import bcfetch from 'bandcamp-fetch';
const discovery = bcfetch.discovery;
const options = await discovery.getAvailableOptions();
const results = await discovery.discover(...);Methods:
Params
params: (DiscoverParams) (optional and all properties optional)genre: (string)subgenre: (string) only valid whengenreis set to something other than 'all'.location: (string)sortBy: (string)category: (number)time: (number)customTags: (Array<string>)size: numberalbumImageFormat: (string | number | ImageFormat)artistImageFormat: (string | number | ImageFormat)merchImageFormat: (string | number | ImageFormat)
To see what values can be set in params, call getAvailableOptions().
Returns
Promise resolving to DiscoverResult.
Continuation
Check the continuation property of the returned result to see if more results are available. To obtain the next set of results, pass the value of continuation to discover():
const results = await discovery.discover(...);
// More results
if (results.continuation) {
const moreResults = await discovery.discover(results.continuation);
...
}Returns
Promise resolving to DiscoverOptions.
Params
params: (DiscoverParams) (optional) the discover params to sanitize.
Returns
Promise resolving to sanitized DiscoverParams.
Returns
Promise resolving to TagsAndLocations, which groups results into tags and locations.
Image API
To access the Image API:
import bcfetch, { ImageFormatFilter } from 'bandcamp-fetch';
const image = bcfetch.image;
const formats = await image.getFormats(ImageFormatFilter.Album);Methods:
Params
filter: (ImageFormatFilter) (optional) if specified, narrows down the result to include only formats applicable to the specified value.
Returns
Promise resolving to Array<ImageFormat>.
Params
target: (string | number | ImageFormat)- If target is string or number, the method finds the image format with matching name or Id (as appropriate).
- If target satisfies the ImageFormat interface constraint, then it is returned as is.
fallbackId: (number) (optional) if no match is found fortarget, try to obtain format with Id matchingfallbackId.
Returns
Promise resolving to matching ImageFormat, or null if none matches target nor fallbackId (if specified).
Band API
A band can be an artist or label. To access the Band API:
import bcfetch from 'bandcamp-fetch';
const band = bcfetch.band;
const info = await band.getInfo(...);Methods:
Params
params: (BandAPIGetInfoParams)bandUrl: (string)imageFormat: (string | number | ImageFormat) (optional)labelId: (number) (optional)
The method tries to assemble the most complete set of data by scraping the following pages (returning immediately at any point the data becomes complete):
- The page referred to by
bandUrl - The 'music' page of the artist or label (
bandUrl/music) - The first album or track in the artist's or label's discography
Sometimes, label information is missing for artists even when they do belong to a label. If you know the labelId of the label that the artist belongs to, you can specify it in params. This will ensure that label will not be null in the artist info. If you pass a label URL to this function, you can find the labelId in the result.
Returns
Promise resolving to Artist or Label.
Params
params: (BandAPIGetLabelArtistsParams)labelUrl: (string)imageFormat: (string | number | ImageFormat) (optional)
Returns
Promise resolving to Array<LabelArtist>.
Params
params: (BandAPIGetDiscographyParams)bandUrl: (string)imageFormat: (string | number | ImageFormat) (optional)
Returns
Promise resolving to Array<Album | Track>.
Album API
To access the Album API:
import bcfetch from 'bandcamp-fetch';
const album = bcfetch.album;
const info = await album.getInfo(...);Methods:
Params
params: (AlbumAPIGetInfoParams)albumUrl: (string)albumImageFormat: (string | number | ImageFormat) (optional)artistImageFormat: (string | number | ImageFormat) (optional)includeRawData: (boolean) (*optional)
Returns
Promise resolving to Album.
If artist URL is not found in the scraped data, then
artist.urlwill be set to the same value aspublisher.url
Track API
To access the Track API:
import bcfetch from 'bandcamp-fetch';
const track = bcfetch.track;
const info = await track.getInfo(...);Methods:
Params
params: (TrackAPIGetInfoParams)trackUrl: (string)albumImageFormat: (string | number | ImageFormat) (optional)artistImageFormat: (string | number | ImageFormat) (optional)includeRawData: (boolean) (*optional)
Returns
Promise resolving to Track.
If artist URL is not found in the scraped data, then
artist.urlwill be set to the same value aspublisher.url
Tag API
To access the Tag API:
import bcfetch from 'bandcamp-fetch';
const tags = await bcfetch.tag.getRelated(...);Methods:
Params
params: (TagAPIGetRelatedParams)tags: (Array<string>)size: (number) (optional)
Returns
Promise resolving to RelatedTags, which has the following properties:
single: list of related tags for each tag queriedcombo: the combined result of all the related tags
Show API
To access the Show API:
import bcfetch from 'bandcamp-fetch';
const show = bcfetch.show;
const list = await show.list(...);Methods:
Each list entry contains basic info about a show. To obtain full details, pass its url to getShow().
Params
params: (ShowAPIListParams) (optional)imageFormat: (string | number | ImageFormat) (optional)
Returns
Promise resolving to Array<Show>.
Params
params: (ShowAPIGetShowParams)showUrl: (string)albumImageFormat: (string | number | ImageFormat) (optional)artistImageFormat: (string | number | ImageFormat) (optional)showImageFormat: (string | number | ImageFormat) (optional)
Returns
Promise resolving to Show.
Article API
To access the Article API:
import bcfetch from 'bandcamp-fetch';
const article = bcfetch.article;
const list = await article.list(...);Methods:
Returns
Promise resolving to Array<ArticleCategorySection>.
Params
params: (ArticleAPIListParams) (optional and all properties optional)categoryUrl: (string)imageFormat: (string | number | ImageFormat)page: (number)
Returns
Promise resolving to ArticleList.
Params
params: (ArticleAPIGetArticleParams)articleUrl: (string)albumImageFormat: (string | number | ImageFormat) (optional)artistImageFormat: (string | number | ImageFormat) (optional)includeRawData: (boolean) (optional)
Returns
Promise resolving to Article.
Fan API
To access the Fan API:
import bcfetch from 'bandcamp-fetch';
const fan = bcfetch.fan;
const info = await fan.getInfo(...);
const collection = await fan.getCollection(...);Methods:
Params
params: (FanAPIGetInfoParams) (optional)username: (string) (optional)imageFormat: (string | number | ImageFormat) (optional)
If username is not specified, result will be obtained for the user of the session tied to the BandcampFetch instance.
Returns
Promise resolving to Fan.
Params
params: (FanAPIGetItemsParams)target: (string | FanItemsContinuation) (optional) if username (string) is specified, returns the first batch of items in the collection. To obtain further items, call the method again but, instead of username, passcontinuationfrom the result of the first call. If there are no further items available,continuationwill benull.imageFormat: (string | number | ImageFormat) (optional)
If target is not specified, result will be obtained for the user of the session tied to the BandcampFetch instance.
Returns
Promise resolving to (FanPageItemsResult | FanContinuationItemsResult)<Album | Track>.
Params
params: (FanAPIGetItemsParams)target: (string | FanItemsContinuation) (optional) if username (string) is specified, returns the first batch of items in the wishlist. To obtain further items, call the method again but, instead of username, passcontinuationfrom the result of the first call. If there are no further items available,continuationwill benull.imageFormat: (string | number | ImageFormat) (optional)
If target is not specified, result will be obtained for the user of the session tied to the BandcampFetch instance.
Returns
Promise resolving to (FanPageItemsResult | FanContinuationItemsResult)<Album | Track>.
Params
params: (FanAPIGetItemsParams)target: (string | FanItemsContinuation) (optional) if username (string) is specified, returns the first batch of artists and labels. To obtain further items, call the method again but, instead of username, passcontinuationfrom the result of the first call. If there are no further items available,continuationwill benull.imageFormat: (string | number | ImageFormat) (optional)
If target is not specified, result will be obtained for the user of the session tied to the BandcampFetch instance.
Returns
Promise resolving to (FanPageItemsResult | FanContinuationItemsResult)<UserKind>.
Each genre is actually a Bandcamp tag, so you can, for example, pass its url to getReleases() of the Tag API.
Params
params: (FanAPIGetItemsParams)target: (string | FanItemsContinuation) (optional) if username (string) is specified, returns the first batch of genres. To obtain further items, call the method again but, instead of username, passcontinuationfrom the result of the first call. If there are no further items available,continuationwill benull.imageFormat: (string | number | ImageFormat) (optional)
If target is not specified, result will be obtained for the user of the session tied to the BandcampFetch instance.
Returns
Promise resolving to (FanPageItemsResult | FanContinuationItemsResult)<Tag>.
Playlist API
To access the Playlist API:
import bcfetch from 'bandcamp-fetch';
// First obtain the fan ID of the user.
const { fanId } = await bcfetch.fan.getInfo({
username: ...
imageFormat: ...
});
// Use the Playlist API to fetch the user's playlists.
const list = await bcfetch.playlist.list({
fanId
});
// Fetch details of the first playlist.
const playlistUrl = list.items[0].url;
const playlist = await bcfetch.playlist.getPlaylist({ playlistUrl });
console.log('Tracks:', playlist.tracks);
// The playlist only contains details of the first 30 tracks.
// If there are more, their IDs will be given in `additionalTrackIds`.
// We can fetch their details too.
if (playlist.additionalTrackIds.length > 0) {
const additionalTracks = await bcfetch.playlist.getAdditionalTracks({
playlist
});
console.log('Additional tracks:', additionalTracks);
}Methods:
Params
params: (PlaylistAPIListParams)- Either:
fanId: (number) the ID of the fan; orcontinuation: (PlaylistListContinuation) continuation data obtained from previous request; used for fetching further items in the list.
imageFormat: (string | number | ImageFormat) (optional)
- Either:
Returns
Promise resolving to PlaylistList.
Params
params: (PlaylistAPIGetPlaylistParams)playlistUrl: (string)artistImageFormat: (string | number | ImageFormat) (optional)trackImageFormat: (string | number | ImageFormat) (optional)playlistImageFormat: (string | number | ImageFormat) (optional)curatorImageFormat: (string | number | ImageFormat) (optional)
Returns
Promise resolving to Playlist.
Params
params: (PlaylistAPIGetPlaylistParams)- playlist: (Playlist) the playlist containing additional tracks.
- Either: (optional)
start: (number) the position of the first ID inadditionalTrackIdsto start fetching from; orfromId: (number) the ID inadditionalTrackIdsto start fetching from.- If both
startandfromIdare omitted, the default would bestart: 0.
count: (number) (optional) the number of tracks to retrieve. If omitted, the default would be to fetch till the end.artistImageFormat: (string | number | ImageFormat) (optional)trackImageFormat: (string | number | ImageFormat) (optional)
Returns
Promise resolving to Array<PlaylistTrack>.
Search API
To access the Search API:
import bcfetch from 'bandcamp-fetch';
const search = bcfetch.search;
const albums = await search.albums(...);
const all = await search.all(...);Cookie requirement
Search requires setting a cookie. You either provide one yourself prior to calling one of the Search API methods, or you let the library obtain one automaticalky. For automatic cookie fetching, you must have puppeteer installed (see Installation). Attempting to search without a cookie and without automatic cookie fetching will result in an error.
Methods:
all(params): search all item typesartistsAndLabels(params): search artists and labelsalbums(params): search albumstracks(params): search tracksfans(params): search fans
Params
params: (SearchAPISearchParams)query: (string)page: (number) (optional) 1 if omittedalbumImageFormat: (string | number | ImageFormat) (optional)artistImageFormat: (string | number | ImageFormat) (optional)
Returns
Promise resolving to SearchResults<T>, where T depends on the item type being searched and can be one of:
- Artist (SearchResultArtist)
- Label (SearchResultLabel)
- Album (SearchResultAlbum)
- Track (SearchResultTrack)
- Fan (SearchResultFan)
You can use the type property to determine the search result item type.
Autocomplete API
To access the Autocomplete API:
import bcfetch from 'bandcamp-fetch';
const autocomplete = bcfetch.autocomplete;
const suggestions = await autocomplete.getSuggestions(...);Methods:
The value property of returned suggestions can be used to set the location or tags property (as the case may be) of params.filters that is passed into getReleases() of the Tag API.
Params
params: (AutocompleteAPIGetSuggestionsParams)query: (string)itemType: (AutocompleteItemType) 'Tag' or 'Location'limit: (number) (optional) (only forItemType.Location) the maximum number of results to return; 5 if omitted.
Returns
- If
params.itemTypeisAutocompleteItemType.Tag, a Promise resolving to Array<AutocompleteTag>. - If
params.itemTypeisAutocompleteItemType.Location, a Promise resolving to Array<AutocompleteLocation>.
Stream API
Stream URLs returned by Bandcamp can sometimes be invalid (perhaps expired). Before playing a stream, you are recommended to test its URL and refresh it if necessary with the Stream API.
To access the Stream API:
import bcfetch from 'bandcamp-fetch';
const stream = bcfetch.stream;
// Test a stream URL
const streamURL = '...';
const testResult = await stream.test(streamUrl);
if (!testResult.ok) {
const refreshedStreamURL = await stream.refresh(streamURL);
}Methods:
Params
url: (string) the URL of the stream to test
Returns
Promise resolving to StreamTestResult:
ok: (boolean) whether the stream is validstatus: (number) the HTTP response status code returned by the test
Params
url: (string) the URL of the stream to refresh
Returns
Promise resolving to the refreshed URL of the stream or null if no valid result was obtained.
Rate Limiting
Each BandcampFetch instance comes with a rate limiter, which limits the number of requests made within a specific time period.
Rate limiting is useful when you need to make a large number of queries and don't want to run the risk of getting rejected by the server for making too many requests within a short time interval. If you get a '429 Too Many Requests' error, then you should consider using the rate limiter.
Each API has a limiter-enabled counterpart which you can access in the following manner:
import bcfetch from 'bandcamp-fetch';
// Album API - no limiter enabled
const albumAPI = bcfetch.album;
// Album API - limiter enabled
const limiterAlbumAPI = bcfetch.limiter.album;The library uses Bottleneck for rate limiting. You can configure the rate limiter like this:
bcfetch.limiter.updateSettings({
maxConcurrent: 10, // default: 5
minTime: 100 // default: 200
});updateSettings() is just a passthrough function to Bottleneck. Check the Bottleneck doc for the list of options you can set.
Cache
Each BandcampFetch instance has an in-memory cache for two types of data (as defined by CacheDataType):
CacheDataType.Page- pages fetched during scrapingCacheDataType.Constants- image formats and discover options
To access the cache:
import bcfetch, { CacheDataType } from 'bandcamp-fetch';
const cache = bcfetch.cache;
cache.setTTL(CacheDataType.Page, 500);Methods:
Params
type: (CacheDataType)TTL: (number) expiry time in seconds (default: 300 forCacheDataType.Pageand 3600 forCacheDataType.Constants)
Params
maxPages: (number)
Params
type: (CacheDataType) (optional)
Logging
Capture debug messages by enabling logging:
// Define logger
const logger = {
debug: (...args) => console.debug('[DEBUG]'.padEnd(10), ...args),
info: (...args) => console.info('[INFO]'.padEnd(10), ...args),
warn: (...args) => console.warn('[WARN]'.padEnd(10), ...args),
error: (...args) => console.error('[ERROR]'.padEnd(10), ...args)
};
// Set logger
bcfetch.setLogger(logger);
// Or pass it to constructor
const bcfetch1 = new BandcampFetch({
logger
});Changelog
v3.2.1
- fix: adapt Playlist and Discovery APIs to site changes.
See the full changelog for older versions.
License
MIT
