diff options
Diffstat (limited to 'src/content/dependencies')
5 files changed, 281 insertions, 45 deletions
diff --git a/src/content/dependencies/generateArtistInfoPage.js b/src/content/dependencies/generateArtistInfoPage.js index cf8ce994..29bc34e6 100644 --- a/src/content/dependencies/generateArtistInfoPage.js +++ b/src/content/dependencies/generateArtistInfoPage.js @@ -14,6 +14,11 @@ export default { ...artist.trackCoverArtistContributions, ], + musicVideoContributions: [ + ...artist.musicVideoArtistContributions, + ...artist.musicVideoContributorContributions, + ], + // Banners and wallpapers don't show up in the artist gallery page, only // cover art. hasGallery: @@ -79,6 +84,12 @@ export default { ? relation('linkArtistGallery', artist) : null), + musicVideosChunkedList: + relation('generateArtistInfoPageMusicVideosChunkedList', artist), + + musicVideosGroupInfo: + relation('generateArtistGroupContributionsInfo', query.musicVideoContributions), + flashesChunkedList: relation('generateArtistInfoPageFlashesChunkedList', artist), @@ -216,6 +227,11 @@ export default { {href: '#art'}, language.$(pageCapsule, 'artList.title')), + !html.isBlank(relations.musicVideosChunkedList) && + html.tag('a', + {href: '#music-videos'}, + language.$(pageCapsule, 'musicVideoList.title')), + !html.isBlank(relations.flashesChunkedList) && html.tag('a', {href: '#flashes'}, @@ -329,6 +345,26 @@ export default { relations.contentHeading.clone() .slots({ tag: 'h2', + attributes: {id: 'music-videos'}, + title: language.$(pageCapsule, 'musicVideoList.title'), + }), + + relations.musicVideosChunkedList.slots({ + groupInfo: + language.encapsulate(pageCapsule, 'groupContributions', capsule => + relations.musicVideosGroupInfo.slots({ + title: language.$(capsule, 'title.artworks'), + showBothColumns: false, + sort: 'count', + countUnit: 'artworks', + })), + }), + ]), + + html.tags([ + relations.contentHeading.clone() + .slots({ + tag: 'h2', attributes: {id: 'flashes'}, title: language.$(pageCapsule, 'flashList.title'), }), diff --git a/src/content/dependencies/generateArtistInfoPageMusicVideosChunk.js b/src/content/dependencies/generateArtistInfoPageMusicVideosChunk.js new file mode 100644 index 00000000..6912d4d6 --- /dev/null +++ b/src/content/dependencies/generateArtistInfoPageMusicVideosChunk.js @@ -0,0 +1,58 @@ +export default { + relations: (relation, artist, album, contribs) => ({ + template: + relation('generateArtistInfoPageChunk'), + + albumLink: + relation('linkAlbum', album), + + albumArtistCredit: + relation('generateArtistCredit', album.artistContribs, []), + + items: + contribs.map(contribs => + relation('generateArtistInfoPageMusicVideosChunkItem', + artist, + contribs)), + }), + + data: (_artist, album, contribs) => ({ + albumDate: + album.date, + + contribDates: + contribs + .flat() + .map(contrib => contrib.date), + }), + + generate: (data, relations, {html, language}) => + relations.template.slots({ + mode: 'album', + + link: + language.encapsulate('artistPage.creditList.album', workingCapsule => { + const creditCapsule = workingCapsule + '.credit'; + const workingOptions = {album: relations.albumLink}; + + relations.albumArtistCredit.setSlots({ + normalStringKey: creditCapsule + '.by', + }); + + if (!html.isBlank(relations.albumArtistCredit)) { + workingCapsule += '.withCredit'; + workingOptions.credit = + html.tag('span', {class: 'by'}, + relations.albumArtistCredit); + } + + return language.$(workingCapsule, workingOptions); + }), + + date: data.albumDate, + dates: data.contribDates, + + list: + html.tag('ul', relations.items), + }), +}; diff --git a/src/content/dependencies/generateArtistInfoPageMusicVideosChunkItem.js b/src/content/dependencies/generateArtistInfoPageMusicVideosChunkItem.js new file mode 100644 index 00000000..8bae860d --- /dev/null +++ b/src/content/dependencies/generateArtistInfoPageMusicVideosChunkItem.js @@ -0,0 +1,118 @@ +import {empty} from '#sugar'; +import {selectRepresentativeArtistContributorContribs} from '#wiki-data'; + +export default { + query(_artist, contribs) { + const query = {}; + + query.musicVideo = contribs[0].thing; + + query.albumOrTrack = query.musicVideo.thing; + + query.album = + (query.albumOrTrack.isAlbum + ? query.albumOrTrack + : query.albumOrTrack.album); + + query.displayedContributions = + selectRepresentativeArtistContributorContribs(contribs); + + return query; + }, + + relations: (relation, query, artist, _contribs) => ({ + template: + relation('generateArtistInfoPageChunkItem'), + + trackLink: + (query.albumOrTrack.isTrack + ? relation('linkTrack', query.albumOrTrack) + : null), + + artistCredit: + relation('generateArtistCredit', + query.musicVideo.artistContribs, + (empty(query.album.artistContribs) + ? [artist.mockSimpleContribution] + : query.album.artistContribs)), + + externalLinks: + query.musicVideo.urls + .map(url => relation('linkExternal', url)), + }), + + data: (query, _artist, contribs) => ({ + date: contribs[0].date, + + for: + (query.albumOrTrack.isAlbum + ? 'album' + : 'track'), + + title: query.musicVideo.title, + label: query.musicVideo.label, + + contribAnnotationParts: + (query.displayedContributions + ? query.displayedContributions + .flatMap(contrib => contrib.annotationParts) + : null), + }), + + generate: (data, relations, {html, language}) => + relations.template.slots({ + annotation: + (data.contribAnnotationParts + ? language.formatUnitList(data.contribAnnotationParts) + : html.blank()), + + content: + language.encapsulate('artistPage.creditList.entry', entryCapsule => { + let workingCapsule = entryCapsule; + let workingOptions = {}; + + workingCapsule += '.' + data.for + '.musicVideo'; + + const musicVideoCapsule = workingCapsule; + + if (data.for === 'track') { + workingOptions.track = + relations.trackLink; + } + + if (data.date) { + workingCapsule += '.withDate'; + workingOptions.date = language.formatDate(data.date); + } + + relations.artistCredit.setSlots({ + normalStringKey: + musicVideoCapsule + '.credit' + + (data.title ? '.alongsideTitle' + : data.label ? '.alongsideLabel' + : ''), + }); + + if (!html.isBlank(relations.artistCredit)) { + workingCapsule += '.withCredit'; + workingOptions.credit = relations.artistCredit; + } + + if (data.title) { + workingCapsule += '.withTitle'; + workingOptions.title = language.sanitize(data.title); + } else if (data.label) { + workingCapsule += '.withLabel'; + workingOptions.label = language.sanitize(data.label); + } + + if (!empty(relations.externalLinks)) { + workingCapsule += '.withLinks'; + workingOptions.links = + language.formatUnitList(relations.externalLinks); + } + + return language.$(workingCapsule, workingOptions); + }), + }), +}; diff --git a/src/content/dependencies/generateArtistInfoPageMusicVideosChunkedList.js b/src/content/dependencies/generateArtistInfoPageMusicVideosChunkedList.js new file mode 100644 index 00000000..588fbbeb --- /dev/null +++ b/src/content/dependencies/generateArtistInfoPageMusicVideosChunkedList.js @@ -0,0 +1,66 @@ +import {chunkByConditions, stitchArrays} from '#sugar'; +import {sortAlbumsTracksChronologically, sortContributionsChronologically} + from '#sort'; + +export default { + query(artist) { + const query = {}; + + const allContributions = [ + ...artist.musicVideoArtistContributions, + ...artist.musicVideoContributorContributions, + ...artist.otherMusicVideoArtistContributionsToOwnAlbums, + ]; + + const getMusicVideo = contrib => + contrib.thing; + + const getAlbumOrTrack = contrib => + getMusicVideo(contrib).thing; + + sortContributionsChronologically( + allContributions, + sortAlbumsTracksChronologically, + {getThing: getAlbumOrTrack}); + + const getAlbum = contrib => + (getAlbumOrTrack(contrib).isTrack + ? getAlbumOrTrack(contrib).album + : getAlbumOrTrack(contrib)); + + query.contribs = + chunkByConditions(allContributions, [ + (a, b) => getAlbum(a) !== getAlbum(b), + ]).map(contribs => + chunkByConditions(contribs, [ + (a, b) => getMusicVideo(a) !== getMusicVideo(b), + ])); + + query.albums = + query.contribs + .map(contribs => contribs[0][0]) + .map(contrib => getAlbum(contrib)); + + return query; + }, + + relations: (relation, query, artist) => ({ + template: + relation('generateArtistInfoPageChunkedList'), + + chunks: + stitchArrays({ + album: query.albums, + contribs: query.contribs, + }).map(({album, contribs}) => + relation('generateArtistInfoPageMusicVideosChunk', + artist, + album, + contribs)), + }), + + generate: (relations) => + relations.template.slots({ + chunks: relations.chunks, + }), +}; diff --git a/src/content/dependencies/generateArtistInfoPageTracksChunkItem.js b/src/content/dependencies/generateArtistInfoPageTracksChunkItem.js index 69d8eebd..22a4a228 100644 --- a/src/content/dependencies/generateArtistInfoPageTracksChunkItem.js +++ b/src/content/dependencies/generateArtistInfoPageTracksChunkItem.js @@ -1,5 +1,6 @@ import {sortAlbumsTracksChronologically} from '#sort'; import {empty} from '#sugar'; +import {selectRepresentativeArtistContributorContribs} from '#wiki-data'; export default { query(artist, contribs, chunkContribs) { @@ -15,51 +16,8 @@ export default { chunkContribs.flat() .some(contrib => +contrib.date !== +query.track.album.date); - const creditedAsNormalArtist = - contribs - .some(contrib => - contrib.thingProperty === 'artistContribs' && - !contrib.isFeaturingCredit); - - const creditedAsContributor = - contribs - .some(contrib => contrib.thingProperty === 'contributorContribs'); - - const annotatedContribs = - contribs - .filter(contrib => !empty(contrib.annotationParts)); - - const annotatedArtistContribs = - annotatedContribs - .filter(contrib => contrib.thingProperty === 'artistContribs'); - - const annotatedContributorContribs = - annotatedContribs - .filter(contrib => contrib.thingProperty === 'contributorContribs'); - - // Don't display annotations associated with crediting in the - // Contributors field if the artist is also credited as an Artist - // *and* the Artist-field contribution is non-annotated. This is - // so that we don't misrepresent the artist - the contributor - // annotation tends to be for "secondary" and performance roles. - // For example, this avoids crediting Marcy Nabors on Renewed - // Return seemingly only for "bass clarinet" when they're also - // the one who composed and arranged Renewed Return! - if ( - creditedAsNormalArtist && - creditedAsContributor && - empty(annotatedArtistContribs) - ) { - query.displayedContributions = null; - } else if ( - !empty(annotatedArtistContribs) || - !empty(annotatedContributorContribs) - ) { - query.displayedContributions = [ - ...annotatedArtistContribs, - ...annotatedContributorContribs, - ]; - } + query.displayedContributions = + selectRepresentativeArtistContributorContribs(contribs); // It's kinda awkward to perform this chronological sort here, // per track, rather than just reusing the one that's done to |