254 lines
8.6 KiB
JavaScript
254 lines
8.6 KiB
JavaScript
const fetch = require('node-fetch');
|
|
const utils = require('./utils.js');
|
|
const parser = require('./parser.js');
|
|
|
|
const cache = {};
|
|
|
|
async function discover(params, options = {}) {
|
|
const imageConstants = await _getImageConstants();
|
|
const opts = {
|
|
imageBaseUrl: imageConstants.baseUrl,
|
|
albumImageFormat: await _parseImageFormatArg(options.albumImageFormat, 9),
|
|
artistImageFormat: await _parseImageFormatArg(options.artistImageFormat, 21)
|
|
};
|
|
|
|
let resultParams;
|
|
return sanitizeDiscoverParams(params)
|
|
.then( sanitizedParams => {
|
|
resultParams = Object.assign({}, sanitizedParams);
|
|
// Passing an 'all' type subgenre (e.g. 'all-metal') in the discover url
|
|
// actually returns far fewer / zero results than without.
|
|
// The Bandcamp site also does not seem to include it in its discover requests...
|
|
if (sanitizedParams.time !== undefined) {
|
|
// If 'time' exists in sanitized params, then we have an 'all' type subgenre
|
|
// - refer to sanitizeDiscoverParams()
|
|
delete sanitizedParams.subgenre;
|
|
}
|
|
return utils.getDiscoverUrl(sanitizedParams);
|
|
})
|
|
.then( url => fetch(url) )
|
|
.then( res => res.json() )
|
|
.then( json => {
|
|
const result = parser.parseDiscoverResults(json, opts);
|
|
result.params = resultParams;
|
|
return result;
|
|
});
|
|
}
|
|
|
|
async function sanitizeDiscoverParams(params) {
|
|
return getDiscoverOptions().then( options => {
|
|
const getOptionValue = (optArr, value, defaultIndex = 0) => {
|
|
if (value !== undefined && optArr) {
|
|
const opt = optArr.find( o => o.value == value );
|
|
if (opt) {
|
|
return opt.value;
|
|
}
|
|
}
|
|
if (optArr) {
|
|
return optArr[defaultIndex].value;
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
}
|
|
const sanitized = {
|
|
genre: getOptionValue(options.genres, params.genre),
|
|
sortBy: getOptionValue(options.sortBys, params.sortBy),
|
|
page: params.page || 0
|
|
};
|
|
if (sanitized.sortBy !== 'rec') {
|
|
// following only valid when sortBy is not 'rec' (artist-recommend)
|
|
const subgenreOptions = options.subgenres[sanitized.genre];
|
|
if (subgenreOptions) { // false if genre is 'all'
|
|
sanitized.subgenre = getOptionValue(subgenreOptions, params.subgenre);
|
|
}
|
|
// 'Time' option only available when there is effectively no subgenre (e.g. genre is 'all'
|
|
// or subgenre is 'all-metal')
|
|
const timeAllowed = sanitized.subgenre === undefined || sanitized.subgenre == subgenreOptions[0].value;
|
|
if (timeAllowed) {
|
|
sanitized.time = getOptionValue(options.times, params.time, 1);
|
|
}
|
|
sanitized.location = getOptionValue(options.locations, params.location);
|
|
sanitized.format = getOptionValue(options.formats, params.format);
|
|
}
|
|
else {
|
|
sanitized.artistRecommendationType = getOptionValue(options.artistRecommendationTypes, params.artistRecommendationType);
|
|
}
|
|
|
|
return sanitized;
|
|
});
|
|
}
|
|
|
|
async function getDiscoverOptions() {
|
|
if (cache.discoverOptions !== undefined) {
|
|
return cache.discoverOptions;
|
|
}
|
|
const url = utils.getSiteUrl();
|
|
return fetch(url)
|
|
.then( res => res.text() )
|
|
.then( html => {
|
|
cache.discoverOptions = parser.parseDiscoverOptions(html);
|
|
return cache.discoverOptions;
|
|
});
|
|
}
|
|
|
|
async function getImageFormat(idOrName) {
|
|
const imageConstants = await _getImageConstants();
|
|
let result = null;
|
|
imageConstants.formats.every( format => {
|
|
if ( (typeof idOrName === 'string' && format.name === idOrName) ||
|
|
(Number.isInteger(idOrName) && format.id === idOrName) ) {
|
|
result = format;
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
return result;
|
|
}
|
|
|
|
async function getImageFormats(filter = '') {
|
|
return _getImageConstants().then( constants => {
|
|
if (filter === 'album') {
|
|
return constants.formats.filter( c => c.name.startsWith('art_') );
|
|
}
|
|
else if (filter === 'artist') {
|
|
return constants.formats.filter( c => c.name.startsWith('bio_') );
|
|
}
|
|
else {
|
|
return constants.formats;
|
|
}
|
|
});
|
|
}
|
|
|
|
async function _getImageConstants() {
|
|
if (cache.imageConstants !== undefined) {
|
|
return cache.imageConstants;
|
|
}
|
|
const url = utils.getSiteUrl();
|
|
return fetch(url)
|
|
.then( res => res.text() )
|
|
.then( html => {
|
|
cache.imageConstants = parser.parseImageConstants(html);
|
|
return cache.imageConstants;
|
|
});
|
|
}
|
|
|
|
async function _parseImageFormatArg(arg, defaultId = null) {
|
|
let result;
|
|
if (typeof arg === 'string' || Number.isInteger(arg)) {
|
|
result = await getImageFormat(arg);
|
|
}
|
|
else if (typeof arg === 'object') {
|
|
result = arg;
|
|
}
|
|
else {
|
|
result = null;
|
|
}
|
|
if (result === null && defaultId !== null) {
|
|
result = await getImageFormat(defaultId);
|
|
}
|
|
return result;
|
|
};
|
|
|
|
async function getAlbumInfo(albumUrl, options = {}) {
|
|
const opts = {
|
|
albumImageFormat: await _parseImageFormatArg(options.albumImageFormat),
|
|
artistImageFormat: await _parseImageFormatArg(options.artistImageFormat),
|
|
includeRawData: options.includeRawData ? true : false
|
|
};
|
|
return fetch(albumUrl)
|
|
.then( res => res.text() )
|
|
.then( html => parser.parseAlbumInfo(html, opts) );
|
|
}
|
|
|
|
async function getTrackInfo(trackUrl, options = {}) {
|
|
const imageConstants = await _getImageConstants();
|
|
const opts = {
|
|
trackUrl,
|
|
imageBaseUrl: imageConstants.baseUrl,
|
|
albumImageFormat: await _parseImageFormatArg(options.albumImageFormat, 9),
|
|
artistImageFormat: await _parseImageFormatArg(options.artistImageFormat),
|
|
includeRawData: options.includeRawData ? true : false
|
|
};
|
|
return fetch(trackUrl)
|
|
.then( res => res.text() )
|
|
.then( html => parser.parseTrackInfo(html, opts) );
|
|
}
|
|
|
|
async function getDiscography(artistOrLabelUrl, options = {}) {
|
|
const imageConstants = await _getImageConstants();
|
|
const opts = {
|
|
imageBaseUrl: imageConstants.baseUrl,
|
|
artistOrLabelUrl,
|
|
imageFormat: await _parseImageFormatArg(options.imageFormat, 9)
|
|
};
|
|
return fetch(utils.getUrl('music', artistOrLabelUrl))
|
|
.then( res => res.text() )
|
|
.then( html => parser.parseDiscography(html, opts) );
|
|
}
|
|
|
|
async function getArtistOrLabelInfo(artistOrLabelUrl, options = {}) {
|
|
const opts = {
|
|
artistOrLabelUrl,
|
|
imageFormat: await _parseImageFormatArg(options.imageFormat)
|
|
};
|
|
// Some pages don't actually show the 'bio' column.
|
|
// The /music page does seem to always show it though, so parse from that.
|
|
return fetch(utils.getUrl('music', artistOrLabelUrl))
|
|
.then( res => res.text() )
|
|
.then( html => parser.parseArtistOrLabelInfo(html, opts) );
|
|
}
|
|
|
|
async function getLabelArtists(labelUrl, options = {}) {
|
|
const opts = {
|
|
labelUrl,
|
|
imageFormat: await _parseImageFormatArg(options.imageFormat)
|
|
};
|
|
return fetch(utils.getUrl('artists', labelUrl))
|
|
.then( res => res.text() )
|
|
.then( html => parser.parseLabelArtists(html, opts) );
|
|
}
|
|
|
|
async function search(params, options = {}) {
|
|
const opts = {
|
|
albumImageFormat: await _parseImageFormatArg(options.albumImageFormat),
|
|
artistImageFormat: await _parseImageFormatArg(options.artistImageFormat)
|
|
};
|
|
return fetch(utils.getSearchUrl(params))
|
|
.then( res => res.text() )
|
|
.then( html => parser.parseSearchResults(html, opts) );
|
|
}
|
|
|
|
async function getAlbumHighlightsByTag(tagUrl, options = {}) {
|
|
const imageConstants = await _getImageConstants();
|
|
const opts = {
|
|
imageBaseUrl: imageConstants.baseUrl,
|
|
imageFormat: await _parseImageFormatArg(options.imageFormat, 9)
|
|
};
|
|
|
|
return fetch(tagUrl)
|
|
.then( res => res.text() )
|
|
.then( html => parser.parseAlbumHighlightsByTag(html, opts) );
|
|
}
|
|
|
|
async function getTags() {
|
|
return fetch(utils.getUrl('tags'))
|
|
.then( res => res.text() )
|
|
.then( html => parser.parseTags(html) );
|
|
}
|
|
|
|
module.exports = {
|
|
discover,
|
|
getDiscoverOptions,
|
|
sanitizeDiscoverParams,
|
|
getImageFormats,
|
|
getImageFormat,
|
|
getAlbumInfo,
|
|
getTrackInfo,
|
|
getDiscography,
|
|
getArtistOrLabelInfo,
|
|
getLabelArtists,
|
|
search,
|
|
getAlbumHighlightsByTag,
|
|
getTags
|
|
}; |