diff --git a/README.md b/README.md index e629610..a4e98bf 100644 --- a/README.md +++ b/README.md @@ -211,6 +211,12 @@ Fetches the contents of the Bandcamp Daily article at `articleUrl`. - artistImageFormat - includeRawData +### `getTagInfo(tagUrl)` + +[**Example**](examples/getTagInfo.js) ([output](examples/getTagInfo_output.txt)) + +Fetches information about the tag referred to by `tagUrl`. + ### `getReleasesByTag(tagUrl, [params], [options])` [**Example**](examples/getReleasesByTag.js) ([output](examples/getReleasesByTag_output.txt)) diff --git a/examples/getTagInfo.js b/examples/getTagInfo.js new file mode 100644 index 0000000..ae4be85 --- /dev/null +++ b/examples/getTagInfo.js @@ -0,0 +1,10 @@ +const bcfetch = require('../'); +const util = require('util'); + +const tagUrl = 'https://bandcamp.com/tag/dark-ambient'; + +bcfetch.getTagInfo(tagUrl).then( results => { + console.log(util.inspect(results, false, null, false)); +}); + + diff --git a/examples/getTagInfo_output.txt b/examples/getTagInfo_output.txt new file mode 100644 index 0000000..624d137 --- /dev/null +++ b/examples/getTagInfo_output.txt @@ -0,0 +1,80 @@ +{ type: 'tag', + name: 'dark ambient', + url: 'https://bandcamp.com/tag/dark-ambient', + value: 'dark-ambient', + relatedTags: + [ { type: 'tag', + name: 'dungeon synth', + url: 'https://bandcamp.com/tag/dungeon-synth', + value: 'dungeon-synth', + isLocation: false }, + { type: 'tag', + name: 'drone ambient', + url: 'https://bandcamp.com/tag/drone-ambient', + value: 'drone-ambient', + isLocation: false }, + { type: 'tag', + name: 'drone', + url: 'https://bandcamp.com/tag/drone', + value: 'drone', + isLocation: false }, + { type: 'tag', + name: 'field recordings', + url: 'https://bandcamp.com/tag/field-recordings', + value: 'field-recordings', + isLocation: false }, + { type: 'tag', + name: 'atmospheric', + url: 'https://bandcamp.com/tag/atmospheric', + value: 'atmospheric', + isLocation: false }, + { type: 'tag', + name: 'soundscape', + url: 'https://bandcamp.com/tag/soundscape', + value: 'soundscape', + isLocation: false }, + { type: 'tag', + name: 'ambient', + url: 'https://bandcamp.com/tag/ambient', + value: 'ambient', + isLocation: false }, + { type: 'tag', + name: 'industrial', + url: 'https://bandcamp.com/tag/industrial', + value: 'industrial', + isLocation: false }, + { type: 'tag', + name: 'harsh noise', + url: 'https://bandcamp.com/tag/harsh-noise', + value: 'harsh-noise', + isLocation: false }, + { type: 'tag', + name: 'noise', + url: 'https://bandcamp.com/tag/noise', + value: 'noise', + isLocation: false }, + { type: 'tag', + name: 'ambient electronic', + url: 'https://bandcamp.com/tag/ambient-electronic', + value: 'ambient-electronic', + isLocation: false }, + { type: 'tag', + name: 'experimental electronic', + url: 'https://bandcamp.com/tag/experimental-electronic', + value: 'experimental-electronic', + isLocation: false }, + { type: 'tag', + name: 'Russia', + url: 'https://bandcamp.com/tag/russia', + value: 'russia', + isLocation: true }, + { type: 'tag', + name: 'soundtrack', + url: 'https://bandcamp.com/tag/soundtrack', + value: 'soundtrack', + isLocation: false }, + { type: 'tag', + name: 'experimental', + url: 'https://bandcamp.com/tag/experimental', + value: 'experimental', + isLocation: false } ] } diff --git a/lib/index.js b/lib/index.js index 3d3ea18..6c42572 100644 --- a/lib/index.js +++ b/lib/index.js @@ -287,6 +287,11 @@ async function getArticle(articleUrl, options = {}) { .then( html => parser.parseArticle(html, opts) ); } +async function getTagInfo(tagUrl) { + return _fetchPage(tagUrl) + .then( html => parser.parseTagInfo(html, {tagUrl}) ); +} + async function getReleasesByTagFilterOptions(tagUrl) { return getReleasesByTagFilterValueNames(tagUrl) .then( filterValueNames => { @@ -410,6 +415,7 @@ module.exports = { getArticleCategories, getArticleList, getArticle, + getTagInfo, getReleasesByTagFilterOptions, getReleasesByTag, searchTag, diff --git a/lib/parser.js b/lib/parser.js index 7b2d6f1..41a0bc8 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -999,6 +999,38 @@ function parseArticle(html, opts) { return article; } +function parseTagInfo(html, opts) { + const $ = cheerio.load(html); + const blob = decode($('#pagedata[data-blob]').attr('data-blob')); + const parsed = JSON.parse(blob); + if (typeof parsed === 'object' && parsed.hub) { + const tag = { + type: 'tag', + name: parsed.hub.name, + url: opts.tagUrl, + value: parsed.hub.norm_name, + relatedTags: [] + }; + if (Array.isArray(parsed.hub.related_tags)) { + parsed.hub.related_tags.forEach( related => { + const relatedTag = { + type: 'tag', + name: related.name, + url: utils.getUrl(related.url), + value: related.norm_name, + isLocation: related.isloc + }; + tag.relatedTags.push(relatedTag); + }); + } + return tag; + } + else { + console.log('Failed to parse tag info'); + return null; + } +} + function parseHubJSPath(html) { const jsMatch = /src="((?:.+?)hub-(?:.+?).js)"/g.exec(html); return jsMatch[1] || null; @@ -1212,6 +1244,7 @@ module.exports = { parseArticleCategories, parseArticleList, parseArticle, + parseTagInfo, parseHubJSPath, parseHubJSFilterValueNames, parseReleasesByTagFilterOptions,