diff --git a/lib/index.js b/lib/index.js
index 1e515a1..12d8253 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -174,12 +174,16 @@ async function getArtistOrLabelInfo(artistOrLabelUrl, options = {}) {
artistOrLabelUrl,
imageFormat: await _parseImageFormatArg(options.imageFormat)
};
+ let url = utils.getUrl('music', artistOrLabelUrl);
+ if (options.labelId) {
+ url += '/?label=' + encodeURIComponent(options.labelId);
+ }
// The landing page of some artists and labels don't actually
// contain the 'bio' column, so we fetch from the
// 'music' page instead. For artists, if the 'music' page does not
// have the artist info, we shall try with an album or track page
// (this is inefficient...perhaps there is a better way?).
- return _fetchPage(utils.getUrl('music', artistOrLabelUrl))
+ return _fetchPage(url)
.then( html => parser.parseArtistOrLabelInfo(html, opts) )
.then( info => {
if (info.type === 'label' || info.name !== '') {
diff --git a/lib/parser.js b/lib/parser.js
index c84fd9b..9a14b96 100644
--- a/lib/parser.js
+++ b/lib/parser.js
@@ -145,44 +145,59 @@ function parseAlbumInfo(html, opts) {
numTracks: basic.numTracks,
imageUrl: utils.reformatImageUrl(basic.image, opts.albumImageFormat),
keywords: basic.keywords,
- description: basic.description,
+ description: basic.description || '',
releaseDate: extra.album_release_date,
artist: {
name: basic.byArtist.name,
- url: basic.byArtist['@id'],
- description: basic.byArtist.description,
- imageUrl: utils.reformatImageUrl(basic.byArtist.image, opts.artistImageFormat)
+ url: basic.byArtist['@id'] || null,
+ description: null,
+ imageUrl: null,
},
+ publisher: null,
+ label: _parseBackToLabelLink($),
releases: [],
tracks: []
};
+ _setPublisher(album, basic, opts.artistImageFormat);
+
if (Array.isArray(basic.albumRelease)) {
- basic.albumRelease.forEach( release => {
+ basic.albumRelease.filter( release => release.musicReleaseFormat ).forEach( release => {
const releaseItem = {
name: release.name,
url: null,
format: release.musicReleaseFormat,
description: release.description || '',
- imageUrl: utils.reformatImageUrl(release.image, opts.albumImageFormat)
+ imageUrl: null
}
- if (release.url) {
- releaseItem.url = !utils.isAbsoluteUrl(release.url) ? utils.getUrl(release.url, album.url) : release.url;
+ if (release['@id']) {
+ releaseItem.url = !utils.isAbsoluteUrl(release['@id']) ? utils.getUrl(release['@id'], album.url) : release['@id'];
+ }
+ if (release.image) {
+ if (Array.isArray(release.image) && release.image[0]) {
+ releaseItem.imageUrl = release.image[0];
+ }
+ }
+ else {
+ let releaseImageArtId = getAdditionalPropertyValue(release, 'art_id');
+ if (releaseImageArtId) {
+ opts.imageBaseUrl + '/img/a' + releaseImageArtId + '_' + opts.albumImageFormat.id + '.jpg'
+ }
}
album.releases.push(releaseItem);
});
}
- if (Array.isArray(basic.track.itemListElement)) {
- basic.track.itemListElement.forEach( track => {
- let trackUrl = track.item['@id'];
+ if (Array.isArray(extra.trackinfo)) {
+ extra.trackinfo.forEach( track => {
+ let trackUrl = track.title_link;
if (!utils.isAbsoluteUrl(trackUrl)) {
trackUrl = utils.getUrl(trackUrl, album.url);
}
album.tracks.push({
- position: track.position,
- name: track.item.name,
+ position: track.track_num,
+ name: track.title,
url: trackUrl,
- duration: getAdditionalPropertyValue(track.item, 'duration_secs'),
- streamUrl: getAdditionalPropertyValue(track.item, 'file_mp3-128') || null
+ duration: track.duration,
+ streamUrl: (track.file && track.file['mp3-128']) || null
});
});
}
@@ -227,15 +242,27 @@ function parseTrackInfo(html, opts) {
releaseDate: extra.current.release_date,
duration: getAdditionalPropertyValue(basic, 'duration_secs'),
streamUrl: extra.trackinfo && extra.trackinfo[0] && extra.trackinfo[0].file && extra.trackinfo[0].file['mp3-128'] ? extra.trackinfo[0].file['mp3-128'] : null,
- artist: {
- name: basic.byArtist.name,
- url: basic.byArtist['@id'],
- description: basic.byArtist.description,
- imageUrl: utils.reformatImageUrl(basic.byArtist.image, opts.artistImageFormat)
- },
+ artist: null,
+ publisher: null,
+ label: _parseBackToLabelLink($),
album: null
}
- if (basic.inAlbum) {
+ let byArtist;
+ if (basic.inAlbum && basic.inAlbum.byArtist) {
+ byArtist = basic.inAlbum.byArtist;
+ }
+ else {
+ byArtist = basic.byArtist;
+ }
+ track.artist = {
+ name: byArtist.name,
+ url: byArtist['@id'] || null,
+ description: null,
+ imageUrl: null
+ }
+ _setPublisher(track, basic, opts.artistImageFormat);
+
+ if (basic.inAlbum && basic.inAlbum['@id']) {
track.album = {
name: basic.inAlbum.name,
url: basic.inAlbum['@id'],
@@ -266,12 +293,9 @@ function parseTrackInfoFromAlbum(html, opts, trackPosition) {
releaseDate: album.releaseDate,
duration: trackData.duration,
streamUrl: trackData.streamUrl,
- artist: {
- name: album.artist.name,
- url: album.artist.url,
- description: album.artist.description,
- imageUrl: album.artist.imageUrl
- },
+ artist: album.artist,
+ publisher: album.publisher,
+ label: album.label,
album: {
name: album.name,
url: album.url,
@@ -407,6 +431,7 @@ function parseDiscography(html, opts) {
function parseArtistOrLabelInfo(html, opts) {
const $ = cheerio.load(html);
+ const bandData = JSON.parse(decode($('script[data-band]').attr('data-band')));
let bioText = $('#bio-text');
let description;
@@ -429,30 +454,22 @@ function parseArtistOrLabelInfo(html, opts) {
description = '';
}
- let isLabel = $('a[href="/artists"]').length;
- let label = null;
- if (!isLabel) {
- let labelLink = $('a.back-to-label-link');
- if (labelLink.length) {
- let linkText = labelLink.find('.back-link-text').html();
- label = {
- name: utils.substrAfter(linkText, '
') || utils.substrBefore(linkText, ' に戻る') || utils.substrBefore(linkText, ' のアイテムをもっと聴く'),
- url: utils.splitUrl(labelLink.attr('href')).base
- };
- }
- }
-
+ let isLabel = bandData.is_label;
const result = {
type: isLabel ? 'label' : 'artist',
- name: $('#band-name-location').find('.title').text(),
- url: opts.artistOrLabelUrl,
+ name: bandData.name,
+ url: bandData.url,
description: description,
location: $('#band-name-location').find('.location').text(),
imageUrl: utils.reformatImageUrl($('img.band-photo').attr('src'), opts.imageFormat)
};
if (!isLabel) {
- result.label = label;
+ result.label = _parseBackToLabelLink($);
}
+ else {
+ result.labelId = bandData.id;
+ }
+
return result;
}
@@ -1047,7 +1064,7 @@ function parseHubJSPath(html) {
function parseHubJSFilterValueNames(js) {
const filterValueNames = {};
- const tObj = /"hubs\/digdeeper\/filter_value":(.+?)}\);/gs.exec(js);
+ const tObj = /"hubs\/digdeeper\/filter_value":(.+?)}\),/gs.exec(js);
if (tObj[1]) {
const t = safeEval(tObj[1]);
if (t && t[0] && Array.isArray(t[0].blocks)) {
@@ -1237,6 +1254,47 @@ function parseSearchLocationResults(json) {
}
}
+function _parseBackToLabelLink($) {
+ let labelLink = $('.back-to-label-link');
+ if (labelLink.length) {
+ let linkText = labelLink.find('.back-link-text').html();
+ label = {
+ name: utils.substrAfter(linkText, '
') ||
+ utils.substrAfter(linkText, '
') ||
+ utils.substrBefore(linkText, ' に戻る') ||
+ utils.substrBefore(linkText, ' のアイテムをもっと聴く'),
+ url: utils.splitUrl(labelLink.attr('href')).base
+ };
+ return label;
+ }
+
+ return null;
+}
+
+function _setPublisher(target, json, imageFormat) {
+ if (json.publisher) {
+ let publisher = {
+ name: json.publisher.name,
+ url: json.publisher['@id'],
+ description: json.publisher.description,
+ imageUrl: utils.reformatImageUrl(json.publisher.image, imageFormat)
+ }
+ target.publisher = publisher;
+
+ // For backward compatibility
+ if (target.artist) {
+ if (target.artist.url === null) {
+ target.artist.url = target.publisher.url;
+ }
+ target.artist.description = target.publisher.description;
+ target.artist.imageUrl = target.publisher.imageUrl;
+ }
+ }
+ else {
+ target.publisher = null;
+ }
+}
+
module.exports = {
parseDiscoverResults,
parseDiscoverOptions,