From 5981f69fac3e0d303425b8df125cd9e705c9eea8 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Fri, 2 Jun 2023 12:42:26 -0300 Subject: content: generateArtistInfoPage: artwork contributions This actually covers the foundations for other types of contribs too. It's hopefully a fair bit cleaner and easier to follow than the previous data processing for this page! --- src/content/dependencies/generateArtistInfoPage.js | 326 ++++++++++++++------- src/util/sugar.js | 8 + 2 files changed, 235 insertions(+), 99 deletions(-) (limited to 'src') diff --git a/src/content/dependencies/generateArtistInfoPage.js b/src/content/dependencies/generateArtistInfoPage.js index 58b5c37c..06baa961 100644 --- a/src/content/dependencies/generateArtistInfoPage.js +++ b/src/content/dependencies/generateArtistInfoPage.js @@ -1,12 +1,23 @@ +import {empty, filterProperties, unique} from '../../util/sugar.js'; + +import { + chunkByProperties, + sortAlbumsTracksChronologically, +} from '../../util/wiki-data.js'; + export default { contentDependencies: [ 'generateArtistNavLinks', 'generatePageLayout', + 'linkAlbum', + 'linkArtist', + 'linkTrack', ], + extraDependencies: ['html', 'language'], + relations(relation, artist) { const relations = {}; - const sections = relations.sections = {}; relations.layout = relation('generatePageLayout'); @@ -14,6 +25,129 @@ export default { relations.artistNavLinks = relation('generateArtistNavLinks', artist); + /* + const hasGallery = + !empty(artist.albumsAsCoverArtist) || + !empty(artist.tracksAsCoverArtist); + */ + + const processContribs = (...contribArrays) => { + const properties = {}; + + const ownContribs = + contribArrays + .map(contribs => contribs.find(({who}) => who === artist)) + .filter(Boolean); + + properties.contributionDescriptions = + ownContribs.map(({what}) => what).filter(Boolean); + + const otherArtistContribs = + contribArrays + .map(contribs => contribs.filter(({who}) => who !== artist)) + .flat(); + + if (!empty(otherArtistContribs)) { + properties.otherArtistLinks = + otherArtistContribs + .map(({who}) => relation('linkArtist', who)); + } + + return properties; + }; + + const sortContributionEntries = (entries, sortFunction) => { + const things = unique(entries.map(({thing}) => thing)); + sortFunction(things); + + const outputArrays = []; + const thingToOutputArray = []; + + for (const thing of things) { + const array = []; + thingToOutputArray[thing] = array; + outputArrays.push(array); + } + + for (const entry of entries) { + thingToOutputArray[entry.thing].push(entry); + } + + return outputArrays.flat(); + }; + + // TODO: Add and integrate wallpaper and banner date fields (#90) + const artContributionEntries = [ + ...artist.albumsAsCoverArtist.map(album => ({ + kind: 'albumCover', + date: album.coverArtDate, + thing: album, + album: album, + track: null, + ...processContribs(album.coverArtistContribs), + })), + + ...artist.albumsAsWallpaperArtist.map(album => ({ + kind: 'albumWallpaper', + date: album.coverArtDate, + thing: album, + album: album, + track: null, + ...processContribs(album.wallpaperArtistContribs), + })), + + ...artist.albumsAsBannerArtist.map(album => ({ + kind: 'albumBanner', + date: album.coverArtDate, + thing: album, + album: album, + track: null, + ...processContribs(album.bannerArtistContribs), + })), + + ...artist.tracksAsCoverArtist.map(track => ({ + kind: 'trackCover', + date: track.coverArtDate, + thing: track, + album: track.album, + track: track, + rerelease: track.originalReleaseTrack !== null, + trackLink: relation('linkTrack', track), + ...processContribs(track.coverArtistContribs), + })), + ]; + + sortContributionEntries(artContributionEntries, sortAlbumsTracksChronologically); + + relations.artContributionChunks = + chunkByProperties(artContributionEntries, ['album', 'date']) + .map(({album, date, chunk}) => ({ + albumLink: relation('linkAlbum', album), + date: +date, + entries: chunk.map(entry => + filterProperties(entry, [ + 'contributionDescriptions', + 'kind', + 'otherArtistLinks', + 'rerelease', + 'trackLink', + ])) + })); + + /* + const commentaryThings = sortAlbumsTracksChronologically([ + ...(artist.albumsAsCommentator ?? []), + ...(artist.tracksAsCommentator ?? []), + ]); + + const commentaryListChunks = chunkByProperties( + commentaryThings.map((thing) => ({ + album: thing.album || thing, + track: thing.album ? thing : null, + })), + ['album']); + */ + return relations; }, @@ -23,7 +157,37 @@ export default { }; }, - generate(data, relations) { + generate(data, relations, {html, language}) { + const addAccentsToEntry = ({ + rerelease, + entry, + otherArtistLinks, + contributionDescriptions, + }) => { + if (rerelease) { + return language.$('artistPage.creditList.entry.rerelease', {entry}); + } + + const options = {entry}; + const parts = ['artistPage.creditList.entry']; + + if (otherArtistLinks) { + parts.push('withArtists'); + options.artists = language.formatConjunctionList(otherArtistLinks); + } + + if (contributionDescriptions) { + parts.push('withContribution'); + options.contribution = language.formatUnitList(contributionDescriptions); + } + + if (parts.length === 1) { + return entry; + } + + return language.formatString(parts.join('.'), options); + }; + return relations.layout .slots({ title: data.name, @@ -33,6 +197,66 @@ export default { mainClasses: ['long-content'], mainContent: [ + !empty(relations.artContributionChunks) && [ + html.tag('h2', + {id: 'art', class: ['content-heading']}, + language.$('artistPage.artList.title')), + + /* + hasGallery && + html.tag('p', + language.$('artistPage.viewArtGallery.orBrowseList', { + link: link.artistGallery(artist, { + text: language.$('artistPage.viewArtGallery.link'), + }) + })), + */ + + /* + !empty(artGroups) && + html.tag('p', + language.$('artistPage.artGroupsLine', { + groups: language.formatUnitList( + artGroups.map(({groupLink, numContributions}) => + language.$('artistPage.groupsLine.item', { + group: groupLink, + contributions: + language.countContributions(numContributions), + }) + ) + ), + })), + */ + + html.tag('dl', + relations.artContributionChunks.flatMap(({albumLink, date, entries}) => [ + html.tag('dt', + language.$('artistPage.creditList.album.withDate', { + album: albumLink, + date: language.formatDate(new Date(date)), + })), + + html.tag('dd', + html.tag('ul', + entries + .map(({kind, trackLink, ...properties}) => ({ + entry: + (kind === 'trackCover' + ? language.$('artistPage.creditList.entry.track', { + track: trackLink, + }) + : html.tag('i', + language.$('artistPage.creditList.entry.album.' + { + albumWallpaper: 'wallpaperArt', + albumBanner: 'bannerArt', + albumCover: 'coverArt', + }[kind]))), + ...properties, + })) + .map(addAccentsToEntry) + .map(entry => html.tag('li', entry)))), + ])), + ], ], navLinkStyle: 'hierarchical', @@ -177,38 +401,6 @@ export function write(artist, {wikiData}) { })); } - const generateEntryAccents = ({ - getArtistString, - language, - original, - entry, - artists, - contrib, - }) => - original - ? language.$('artistPage.creditList.entry.rerelease', {entry}) - : !empty(artists) - ? contrib.what || contrib.whatArray?.length - ? language.$('artistPage.creditList.entry.withArtists.withContribution', { - entry, - artists: getArtistString(artists), - contribution: contrib.whatArray - ? language.formatUnitList(contrib.whatArray) - : contrib.what, - }) - : language.$('artistPage.creditList.entry.withArtists', { - entry, - artists: getArtistString(artists), - }) - : contrib.what || contrib.whatArray?.length - ? language.$('artistPage.creditList.entry.withContribution', { - entry, - contribution: contrib.whatArray - ? language.formatUnitList(contrib.whatArray) - : contrib.what, - }) - : entry; - const unbound_generateTrackList = (chunks, { getArtistString, html, @@ -467,71 +659,7 @@ export function write(artist, {wikiData}) { generateTrackList(trackListChunks), ]), - ...html.fragment( - !empty(artThingsAll) && [ - html.tag('h2', - {id: 'art', class: ['content-heading']}, - language.$('artistPage.artList.title')), - - hasGallery && - html.tag('p', - language.$('artistPage.viewArtGallery.orBrowseList', { - link: link.artistGallery(artist, { - text: language.$('artistPage.viewArtGallery.link'), - }) - })), - - !empty(artGroups) && - html.tag('p', - language.$('artistPage.artGroupsLine', { - groups: language.formatUnitList( - artGroups.map(({group, contributions}) => - language.$('artistPage.groupsLine.item', { - group: link.groupInfo(group), - contributions: - language.countContributions( - contributions - ), - }) - ) - ), - })), - - html.tag('dl', - artListChunks.flatMap(({date, album, chunk}) => [ - html.tag('dt', language.$('artistPage.creditList.album.withDate', { - album: link.album(album), - date: language.formatDate(date), - })), - - html.tag('dd', - html.tag('ul', - chunk - .map(({track, key, ...props}) => ({ - ...props, - entry: - track - ? language.$('artistPage.creditList.entry.track', { - track: link.track(track), - }) - : html.tag('i', - language.$('artistPage.creditList.entry.album.' + { - wallpaperArtistContribs: - 'wallpaperArt', - bannerArtistContribs: - 'bannerArt', - coverArtistContribs: - 'coverArt', - }[key])), - })) - .map((opts) => generateEntryAccents({ - getArtistString, - language, - ...opts, - })) - .map(row => html.tag('li', row)))), - ])), - ]), + ...html.fragment( wikiInfo.enableFlashesAndGames && diff --git a/src/util/sugar.js b/src/util/sugar.js index 0362e327..6ab70bc6 100644 --- a/src/util/sugar.js +++ b/src/util/sugar.js @@ -82,6 +82,14 @@ export const compareArrays = (arr1, arr2, {checkOrder = true} = {}) => export const withEntries = (obj, fn) => Object.fromEntries(fn(Object.entries(obj))); +export function filterProperties(obj, properties) { + const set = new Set(properties); + return Object.fromEntries( + Object + .entries(obj) + .filter(([key]) => set.has(key))); +} + export function queue(array, max = 50) { if (max === 0) { return array.map((fn) => fn()); -- cgit 1.3.0-6-gf8a5