diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/page/album.js | 381 | ||||
-rw-r--r-- | src/page/index.js | 5 | ||||
-rwxr-xr-x | src/upd8.js | 576 | ||||
-rw-r--r-- | src/util/serialize.js | 71 | ||||
-rw-r--r-- | src/util/wiki-data.js | 31 |
5 files changed, 578 insertions, 486 deletions
diff --git a/src/page/album.js b/src/page/album.js new file mode 100644 index 00000000..f8597790 --- /dev/null +++ b/src/page/album.js @@ -0,0 +1,381 @@ +// Album page specification. +// +// Also exports utility functions: +// - generateAlbumSidebar +// - generateAlbumNavLinks +// - generateAlbumChronologyLinks + +import fixWS from 'fix-whitespace'; + +import { + getAlbumCover, + getAlbumListTag, + getTotalDuration +} from '../util/wiki-data.js'; + +import { + getLinkThemeString, + getThemeString +} from '../util/colors.js'; + +import * as html from '../util/html.js'; + +export function targets({wikiData}) { + return wikiData.albumData; +} + +export function write(album, {wikiData}) { + const { wikiInfo } = wikiData; + + const trackToListItem = (track, {getArtistString, link, strings}) => { + const itemOpts = { + duration: strings.count.duration(track.duration), + track: link.track(track) + }; + return `<li style="${getLinkThemeString(track.color)}">${ + (track.artists === album.artists + ? strings('trackList.item.withDuration', itemOpts) + : strings('trackList.item.withDuration.withArtists', { + ...itemOpts, + by: `<span class="by">${ + strings('trackList.item.withArtists.by', { + artists: getArtistString(track.artists) + }) + }</span>` + })) + }</li>`; + }; + + const commentaryEntries = [album, ...album.tracks].filter(x => x.commentary).length; + const albumDuration = getTotalDuration(album.tracks); + + const listTag = getAlbumListTag(album); + + const data = { + type: 'data', + path: ['album', album.directory], + data: ({ + serializeContribs, + serializeCover, + serializeGroupsForAlbum, + serializeLink + }) => ({ + name: album.name, + directory: album.directory, + dates: { + released: album.date, + trackArtAdded: album.trackArtDate, + coverArtAdded: album.coverArtDate, + addedToWiki: album.dateAdded + }, + duration: albumDuration, + color: album.color, + cover: serializeCover(album, getAlbumCover), + artists: serializeContribs(album.artists || []), + coverArtists: serializeContribs(album.coverArtists || []), + wallpaperArtists: serializeContribs(album.wallpaperArtists || []), + bannerArtists: serializeContribs(album.bannerArtists || []), + groups: serializeGroupsForAlbum(album), + trackGroups: album.trackGroups?.map(trackGroup => ({ + name: trackGroup.name, + color: trackGroup.color, + tracks: trackGroup.tracks.map(track => track.directory) + })), + tracks: album.tracks.map(track => ({ + link: serializeLink(track), + duration: track.duration + })) + }) + }; + + const page = { + type: 'page', + path: ['album', album.directory], + page: ({ + chronologyLinks, + fancifyURL, + generateCoverLink, + getAlbumStylesheet, + getArtistString, + link, + strings, + transformMultiline + }) => ({ + title: strings('albumPage.title', {album: album.name}), + stylesheet: getAlbumStylesheet(album), + theme: getThemeString(album.color, [ + `--album-directory: ${album.directory}` + ]), + + banner: album.bannerArtists && { + dimensions: album.bannerDimensions, + path: ['media.albumBanner', album.directory], + alt: strings('misc.alt.albumBanner'), + position: 'top' + }, + + main: { + content: fixWS` + ${generateCoverLink({ + path: ['media.albumCover', album.directory], + alt: strings('misc.alt.albumCover'), + tags: album.artTags + })} + <h1>${strings('albumPage.title', {album: album.name})}</h1> + <p> + ${[ + album.artists && strings('releaseInfo.by', { + artists: getArtistString(album.artists, { + showContrib: true, + showIcons: true + }) + }), + album.coverArtists && strings('releaseInfo.coverArtBy', { + artists: getArtistString(album.coverArtists, { + showContrib: true, + showIcons: true + }) + }), + album.wallpaperArtists && strings('releaseInfo.wallpaperArtBy', { + artists: getArtistString(album.wallpaperArtists, { + showContrib: true, + showIcons: true + }) + }), + album.bannerArtists && strings('releaseInfo.bannerArtBy', { + artists: getArtistString(album.bannerArtists, { + showContrib: true, + showIcons: true + }) + }), + strings('releaseInfo.released', { + date: strings.count.date(album.date) + }), + +album.coverArtDate !== +album.date && strings('releaseInfo.artReleased', { + date: strings.count.date(album.coverArtDate) + }), + strings('releaseInfo.duration', { + duration: strings.count.duration(albumDuration, {approximate: album.tracks.length > 1}) + }) + ].filter(Boolean).join('<br>\n')} + </p> + ${commentaryEntries && `<p>${ + strings('releaseInfo.viewCommentary', { + link: link.albumCommentary(album, { + text: strings('releaseInfo.viewCommentary.link') + }) + }) + }</p>`} + ${album.urls.length && `<p>${ + strings('releaseInfo.listenOn', { + links: strings.list.or(album.urls.map(url => fancifyURL(url, {album: true}))) + }) + }</p>`} + ${album.trackGroups ? fixWS` + <dl class="album-group-list"> + ${album.trackGroups.map(({ name, color, startIndex, tracks }) => fixWS` + <dt>${ + strings('trackList.group', { + duration: strings.count.duration(getTotalDuration(tracks), {approximate: tracks.length > 1}), + group: name + }) + }</dt> + <dd><${listTag === 'ol' ? `ol start="${startIndex + 1}"` : listTag}> + ${tracks.map(t => trackToListItem(t, {getArtistString, link, strings})).join('\n')} + </${listTag}></dd> + `).join('\n')} + </dl> + ` : fixWS` + <${listTag}> + ${album.tracks.map(t => trackToListItem(t, {getArtistString, link, strings})).join('\n')} + </${listTag}> + `} + <p> + ${[ + strings('releaseInfo.addedToWiki', { + date: strings.count.date(album.dateAdded) + }) + ].filter(Boolean).join('<br>\n')} + </p> + ${album.commentary && fixWS` + <p>${strings('releaseInfo.artistCommentary')}</p> + <blockquote> + ${transformMultiline(album.commentary)} + </blockquote> + `} + ` + }, + + sidebarLeft: generateAlbumSidebar(album, null, { + fancifyURL, + link, + strings, + transformMultiline, + wikiData + }), + + nav: { + links: [ + {toHome: true}, + { + html: strings('albumPage.nav.album', { + album: link.album(album, {class: 'current'}) + }) + }, + album.tracks.length > 1 && + { + divider: false, + html: generateAlbumNavLinks(album, null, {link, strings}) + } + ], + content: html.tag('div', generateAlbumChronologyLinks(album, null, {chronologyLinks})) + } + }) + }; + + return [page, data]; +} + +export function generateAlbumSidebar(album, currentTrack, { + fancifyURL, + link, + strings, + transformMultiline, + wikiData +}) { + const listTag = getAlbumListTag(album); + + const trackGroups = album.trackGroups || [{ + name: strings('albumSidebar.trackList.fallbackGroupName'), + color: album.color, + startIndex: 0, + tracks: album.tracks + }]; + + const trackToListItem = track => html.tag('li', + {class: track === currentTrack && 'current'}, + strings('albumSidebar.trackList.item', { + track: link.track(track) + })); + + const trackListPart = fixWS` + <h1>${link.album(album)}</h1> + ${trackGroups.map(({ name, color, startIndex, tracks }) => + html.tag('details', { + // Leave side8ar track groups collapsed on al8um homepage, + // since there's already a view of all the groups expanded + // in the main content area. + open: currentTrack && tracks.includes(currentTrack), + class: tracks.includes(currentTrack) && 'current' + }, [ + html.tag('summary', + {style: getLinkThemeString(color)}, + (listTag === 'ol' + ? strings('albumSidebar.trackList.group.withRange', { + group: `<span class="group-name">${name}</span>`, + range: `${startIndex + 1}–${startIndex + tracks.length}` + }) + : strings('albumSidebar.trackList.group', { + group: `<span class="group-name">${name}</span>` + })) + ), + fixWS` + <${listTag === 'ol' ? `ol start="${startIndex + 1}"` : listTag}> + ${tracks.map(trackToListItem).join('\n')} + </${listTag}> + ` + ])).join('\n')} + `; + + const { groups } = album; + + const groupParts = groups.map(group => { + const index = group.albums.indexOf(album); + const next = group.albums[index + 1]; + const previous = group.albums[index - 1]; + return {group, next, previous}; + }).map(({group, next, previous}) => fixWS` + <h1>${ + strings('albumSidebar.groupBox.title', { + group: link.groupInfo(group) + }) + }</h1> + ${!currentTrack && transformMultiline(group.descriptionShort)} + ${group.urls.length && `<p>${ + strings('releaseInfo.visitOn', { + links: strings.list.or(group.urls.map(url => fancifyURL(url))) + }) + }</p>`} + ${!currentTrack && fixWS` + ${next && `<p class="group-chronology-link">${ + strings('albumSidebar.groupBox.next', { + album: link.album(next) + }) + }</p>`} + ${previous && `<p class="group-chronology-link">${ + strings('albumSidebar.groupBox.previous', { + album: link.album(previous) + }) + }</p>`} + `} + `); + + if (groupParts.length) { + if (currentTrack) { + const combinedGroupPart = groupParts.join('\n<hr>\n'); + return { + multiple: [ + trackListPart, + combinedGroupPart + ] + }; + } else { + return { + multiple: [ + ...groupParts, + trackListPart + ] + }; + } + } else { + return { + content: trackListPart + }; + } +} + +export function generateAlbumNavLinks(album, currentTrack, {link, strings}) { + if (album.tracks.length <= 1) { + return ''; + } + + const previousNextLinks = currentTrack && generatePreviousNextLinks(currentTrack, { + link, strings, + data: album.tracks, + linkKey: 'track' + }); + const randomLink = `<a href="#" data-random="track-in-album" id="random-button">${ + (currentTrack + ? strings('trackPage.nav.random') + : strings('albumPage.nav.randomTrack')) + }</a>`; + + return (previousNextLinks + ? `(${previousNextLinks}<span class="js-hide-until-data">, ${randomLink}</span>)` + : `<span class="js-hide-until-data">(${randomLink})</span>`); +} + +export function generateAlbumChronologyLinks(album, currentTrack, {chronologyLinks}) { + return [ + currentTrack && chronologyLinks(currentTrack, { + contribKey: 'artists', + getThings: artist => [...artist.tracks.asArtist, ...artist.tracks.asContributor], + headingString: 'misc.chronology.heading.track' + }), + chronologyLinks(currentTrack || album, { + contribKey: 'coverArtists', + getThings: artist => [...artist.albums.asCoverArtist, ...artist.tracks.asCoverArtist], + headingString: 'misc.chronology.heading.coverArt' + }) + ].filter(Boolean).join('\n'); +} diff --git a/src/page/index.js b/src/page/index.js new file mode 100644 index 00000000..ca782389 --- /dev/null +++ b/src/page/index.js @@ -0,0 +1,5 @@ +// NB: This is the index for the page/ directory and contains exports for all +// other modules here! It's not the page spec for the homepage - see +// homepage.js for that. + +export * as album from './album.js'; diff --git a/src/upd8.js b/src/upd8.js index 94fab3b8..621cae57 100755 --- a/src/upd8.js +++ b/src/upd8.js @@ -109,8 +109,10 @@ import { unlink } from 'fs/promises'; -import find from './util/find.js'; import genThumbs from './gen-thumbs.js'; +import * as pageSpecs from './page/index.js'; + +import find from './util/find.js'; import * as html from './util/html.js'; import unbound_link from './util/link.js'; @@ -142,16 +144,30 @@ import { import { chunkByConditions, chunkByProperties, + getAlbumCover, + getAlbumListTag, getAllTracks, getArtistCommentary, getArtistNumContributions, + getFlashCover, getKebabCase, + getTotalDuration, + getTrackCover, sortByArtDate, sortByDate, sortByName } from './util/wiki-data.js'; import { + serializeContribs, + serializeCover, + serializeGroupsForAlbum, + serializeGroupsForTrack, + serializeImagePaths, + serializeLink +} from './util/serialize.js'; + +import { bindOpts, call, filterEmptyLines, @@ -1488,10 +1504,6 @@ function getDurationInSeconds(string) { } } -function getTotalDuration(tracks) { - return tracks.reduce((duration, track) => duration + track.duration, 0); -} - const stringifyIndent = 0; const toRefs = (label, objectOrArray) => { @@ -1650,71 +1662,6 @@ function img({ } } -function serializeImagePaths(original) { - return { - original, - medium: thumb.medium(original), - small: thumb.small(original) - }; -} - -function serializeLink(thing) { - const ret = {}; - ret.name = thing.name; - ret.directory = thing.directory; - if (thing.color) ret.color = thing.color; - return ret; -} - -function serializeContribs(contribs) { - return contribs.map(({ who, what }) => { - const ret = {}; - ret.artist = serializeLink(who); - if (what) ret.contribution = what; - return ret; - }); -} - -function serializeCover(thing, pathFunction) { - const coverPath = pathFunction(thing, { - to: urls.from('media.root').to - }); - - const { artTags } = thing; - - const cwTags = artTags.filter(tag => tag.isCW); - const linkTags = artTags.filter(tag => !tag.isCW); - - return { - paths: serializeImagePaths(coverPath), - tags: linkTags.map(serializeLink), - warnings: cwTags.map(tag => tag.name) - }; -} - -function serializeGroupsForAlbum(album) { - return album.groups.map(group => { - const index = group.albums.indexOf(album); - const next = group.albums[index + 1] || null; - const previous = group.albums[index - 1] || null; - return {group, index, next, previous}; - }).map(({group, index, next, previous}) => ({ - link: serializeLink(group), - descriptionShort: group.descriptionShort, - albumIndex: index, - nextAlbum: next && serializeLink(next), - previousAlbum: previous && serializeLink(previous), - urls: group.urls - })); -} - -function serializeGroupsForTrack(track) { - return track.album.groups.map(group => ({ - link: serializeLink(group), - urls: group.urls, - })); -} - function validateWritePath(path, urlGroup) { if (!Array.isArray(path)) { return {error: `Expected array, got ${path}`}; @@ -2686,218 +2633,6 @@ function writeIndexAndTrackPagesForAlbum(album) { } */ -function writeAlbumPages({wikiData}) { - return wikiData.albumData.map(album => writeAlbumPage(album, {wikiData})); -} - -function writeAlbumPage(album, {wikiData}) { - const { wikiInfo } = wikiData; - - const trackToListItem = (track, {getArtistString, link, strings}) => { - const itemOpts = { - duration: strings.count.duration(track.duration), - track: link.track(track) - }; - return `<li style="${getLinkThemeString(track.color)}">${ - (track.artists === album.artists - ? strings('trackList.item.withDuration', itemOpts) - : strings('trackList.item.withDuration.withArtists', { - ...itemOpts, - by: `<span class="by">${ - strings('trackList.item.withArtists.by', { - artists: getArtistString(track.artists) - }) - }</span>` - })) - }</li>`; - }; - - const commentaryEntries = [album, ...album.tracks].filter(x => x.commentary).length; - const albumDuration = getTotalDuration(album.tracks); - - const listTag = getAlbumListTag(album); - - const data = { - type: 'data', - path: ['album', album.directory], - data: () => ({ - name: album.name, - directory: album.directory, - dates: { - released: album.date, - trackArtAdded: album.trackArtDate, - coverArtAdded: album.coverArtDate, - addedToWiki: album.dateAdded - }, - duration: albumDuration, - color: album.color, - cover: serializeCover(album, getAlbumCover), - artists: serializeContribs(album.artists || []), - coverArtists: serializeContribs(album.coverArtists || []), - wallpaperArtists: serializeContribs(album.wallpaperArtists || []), - bannerArtists: serializeContribs(album.bannerArtists || []), - groups: serializeGroupsForAlbum(album), - trackGroups: album.trackGroups?.map(trackGroup => ({ - name: trackGroup.name, - color: trackGroup.color, - tracks: trackGroup.tracks.map(track => track.directory) - })), - tracks: album.tracks.map(track => ({ - link: serializeLink(track), - duration: track.duration - })) - }) - }; - - const page = { - type: 'page', - path: ['album', album.directory], - page: ({ - generateCoverLink, - getAlbumStylesheet, - getArtistString, - link, - strings, - transformMultiline - }) => ({ - title: strings('albumPage.title', {album: album.name}), - stylesheet: getAlbumStylesheet(album), - theme: getThemeString(album.color, [ - `--album-directory: ${album.directory}` - ]), - - banner: album.bannerArtists && { - dimensions: album.bannerDimensions, - path: ['media.albumBanner', album.directory], - alt: strings('misc.alt.albumBanner'), - position: 'top' - }, - - main: { - content: fixWS` - ${generateCoverLink({ - path: ['media.albumCover', album.directory], - alt: strings('misc.alt.albumCover'), - tags: album.artTags - })} - <h1>${strings('albumPage.title', {album: album.name})}</h1> - <p> - ${[ - album.artists && strings('releaseInfo.by', { - artists: getArtistString(album.artists, { - showContrib: true, - showIcons: true - }) - }), - album.coverArtists && strings('releaseInfo.coverArtBy', { - artists: getArtistString(album.coverArtists, { - showContrib: true, - showIcons: true - }) - }), - album.wallpaperArtists && strings('releaseInfo.wallpaperArtBy', { - artists: getArtistString(album.wallpaperArtists, { - showContrib: true, - showIcons: true - }) - }), - album.bannerArtists && strings('releaseInfo.bannerArtBy', { - artists: getArtistString(album.bannerArtists, { - showContrib: true, - showIcons: true - }) - }), - strings('releaseInfo.released', { - date: strings.count.date(album.date) - }), - +album.coverArtDate !== +album.date && strings('releaseInfo.artReleased', { - date: strings.count.date(album.coverArtDate) - }), - strings('releaseInfo.duration', { - duration: strings.count.duration(albumDuration, {approximate: album.tracks.length > 1}) - }) - ].filter(Boolean).join('<br>\n')} - </p> - ${commentaryEntries && `<p>${ - strings('releaseInfo.viewCommentary', { - link: link.albumCommentary(album, { - text: strings('releaseInfo.viewCommentary.link') - }) - }) - }</p>`} - ${album.urls.length && `<p>${ - strings('releaseInfo.listenOn', { - links: strings.list.or(album.urls.map(url => fancifyURL(url, {album: true, strings}))) - }) - }</p>`} - ${album.trackGroups ? fixWS` - <dl class="album-group-list"> - ${album.trackGroups.map(({ name, color, startIndex, tracks }) => fixWS` - <dt>${ - strings('trackList.group', { - duration: strings.count.duration(getTotalDuration(tracks), {approximate: tracks.length > 1}), - group: name - }) - }</dt> - <dd><${listTag === 'ol' ? `ol start="${startIndex + 1}"` : listTag}> - ${tracks.map(t => trackToListItem(t, {getArtistString, link, strings})).join('\n')} - </${listTag}></dd> - `).join('\n')} - </dl> - ` : fixWS` - <${listTag}> - ${album.tracks.map(t => trackToListItem(t, {getArtistString, link, strings})).join('\n')} - </${listTag}> - `} - <p> - ${[ - strings('releaseInfo.addedToWiki', { - date: strings.count.date(album.dateAdded) - }) - ].filter(Boolean).join('<br>\n')} - </p> - ${album.commentary && fixWS` - <p>${strings('releaseInfo.artistCommentary')}</p> - <blockquote> - ${transformMultiline(album.commentary)} - </blockquote> - `} - ` - }, - - sidebarLeft: generateSidebarForAlbum(album, { - link, - strings, - transformMultiline, - wikiData - }), - - nav: { - links: [ - {toHome: true}, - { - html: strings('albumPage.nav.album', { - album: link.album(album, {class: 'current'}) - }) - }, - album.tracks.length > 1 && - { - divider: false, - html: generateAlbumNavLinks(album, null, {link, strings}) - } - ], - content: fixWS` - <div> - ${generateAlbumChronologyLinks(album, null, {link, strings})} - </div> - ` - } - }) - }; - - return [page, data]; -} - function getAlbumStylesheet(album, {to}) { return [ album.wallpaperArtists && fixWS` @@ -5068,14 +4803,6 @@ function getTagDirectory({name}) { return getKebabCase(name); } -function getAlbumListTag(album) { - if (album.directory === UNRELEASED_TRACKS_DIRECTORY) { - return 'ul'; - } else { - return 'ol'; - } -} - function fancifyURL(url, {strings, album = false} = {}) { const domain = new URL(url).hostname; return fixWS`<a href="${url}" class="nowrap">${ @@ -5196,156 +4923,6 @@ function chronologyLinks(currentThing, { }).filter(Boolean).join('\n'); } -function generateAlbumNavLinks(album, currentTrack, {link, strings}) { - if (album.tracks.length <= 1) { - return ''; - } - - const previousNextLinks = currentTrack && generatePreviousNextLinks(currentTrack, { - link, strings, - data: album.tracks, - linkKey: 'track' - }); - const randomLink = `<a href="#" data-random="track-in-album" id="random-button">${ - (currentTrack - ? strings('trackPage.nav.random') - : strings('albumPage.nav.randomTrack')) - }</a>`; - - return (previousNextLinks - ? `(${previousNextLinks}<span class="js-hide-until-data">, ${randomLink}</span>)` - : `<span class="js-hide-until-data">(${randomLink})</span>`); -} - -function generateAlbumChronologyLinks(album, currentTrack, {link, strings}) { - return [ - currentTrack && chronologyLinks(currentTrack, { - contribKey: 'artists', - getThings: artist => [...artist.tracks.asArtist, ...artist.tracks.asContributor], - headingString: 'misc.chronology.heading.track', - strings, - link, - wikiData - }), - chronologyLinks(currentTrack || album, { - contribKey: 'coverArtists', - getThings: artist => [...artist.albums.asCoverArtist, ...artist.tracks.asCoverArtist], - headingString: 'misc.chronology.heading.coverArt', - link, - strings, - wikiData - }) - ].filter(Boolean).join('\n'); -} - -function generateSidebarForAlbum(album, { - currentTrack = null, - link, - strings, - transformMultiline, - wikiData -}) { - const listTag = getAlbumListTag(album); - - const trackGroups = album.trackGroups || [{ - name: strings('albumSidebar.trackList.fallbackGroupName'), - color: album.color, - startIndex: 0, - tracks: album.tracks - }]; - - const trackToListItem = track => `<li ${classes(track === currentTrack && 'current')}>${ - strings('albumSidebar.trackList.item', { - track: link.track(track) - }) - }</li>`; - - const trackListPart = fixWS` - <h1>${link.album(album)}</h1> - ${trackGroups.map(({ name, color, startIndex, tracks }) => - html.tag('details', { - // Leave side8ar track groups collapsed on al8um homepage, - // since there's already a view of all the groups expanded - // in the main content area. - open: currentTrack && tracks.includes(currentTrack), - class: tracks.includes(currentTrack) && 'current' - }, [ - html.tag('summary', - {style: getLinkThemeString(color)}, - (listTag === 'ol' - ? strings('albumSidebar.trackList.group.withRange', { - group: `<span class="group-name">${name}</span>`, - range: `${startIndex + 1}–${startIndex + tracks.length}` - }) - : strings('albumSidebar.trackList.group', { - group: `<span class="group-name">${name}</span>` - })) - ), - fixWS` - <${listTag === 'ol' ? `ol start="${startIndex + 1}"` : listTag}> - ${tracks.map(trackToListItem).join('\n')} - </${listTag}> - ` - ])).join('\n')} - `; - - const { groups } = album; - - const groupParts = groups.map(group => { - const index = group.albums.indexOf(album); - const next = group.albums[index + 1]; - const previous = group.albums[index - 1]; - return {group, next, previous}; - }).map(({group, next, previous}) => fixWS` - <h1>${ - strings('albumSidebar.groupBox.title', { - group: link.groupInfo(group) - }) - }</h1> - ${!currentTrack && transformMultiline(group.descriptionShort)} - ${group.urls.length && `<p>${ - strings('releaseInfo.visitOn', { - links: strings.list.or(group.urls.map(url => fancifyURL(url, {strings}))) - }) - }</p>`} - ${!currentTrack && fixWS` - ${next && `<p class="group-chronology-link">${ - strings('albumSidebar.groupBox.next', { - album: link.album(next) - }) - }</p>`} - ${previous && `<p class="group-chronology-link">${ - strings('albumSidebar.groupBox.previous', { - album: link.album(previous) - }) - }</p>`} - `} - `); - - if (groupParts.length) { - if (currentTrack) { - const combinedGroupPart = groupParts.join('\n<hr>\n'); - return { - multiple: [ - trackListPart, - combinedGroupPart - ] - }; - } else { - return { - multiple: [ - ...groupParts, - trackListPart - ] - }; - } - } else { - return { - content: trackListPart - }; - } -} - function generateSidebarForGroup(currentGroup, isGallery, {link, strings, wikiData}) { const { groupCategoryData, wikiInfo } = wikiData; @@ -5606,28 +5183,6 @@ function linkAnythingMan(anythingMan, {link, wikiData, ...opts}) { ) } -function getAlbumCover(album, {to}) { - return to('media.albumCover', album.directory); -} - -function getTrackCover(track, {to}) { - // Some al8ums don't have any track art at all, and in those, every track - // just inherits the al8um's own cover art. - if (track.coverArtists === null) { - return getAlbumCover(track.album, {to}); - } else { - return to('media.trackCover', track.album.directory, track.directory); - } -} - -function getFlashCover(flash, {to}) { - return to('media.flashArt', flash.directory); -} - -function getFlashLink(flash) { - return `https://homestuck.com/story/${flash.page}`; -} - function classes(...args) { const values = args.filter(Boolean); return `class="${values.join(' ')}"`; @@ -6316,6 +5871,7 @@ async function main() { await writeSymlinks(); await writeSharedFilesAndPages({strings: defaultStrings, wikiData}); + /* const buildDictionary = { misc: writeMiscellaneousPages, news: writeNewsPages, @@ -6329,12 +5885,14 @@ async function main() { artist: writeArtistPages, flash: writeFlashPages }; + */ + + const buildDictionary = pageSpecs; const buildSteps = (writeAll ? Object.values(buildDictionary) : (Object.entries(buildDictionary) - .filter(([ flag ]) => writeFlags[flag]) - .map(([ flag, fn ]) => fn))); + .filter(([ flag ]) => writeFlags[flag]))); // *NB: While what's 8elow is 8asically still true in principle, the // format is QUITE DIFFERENT than what's descri8ed here! There @@ -6351,18 +5909,27 @@ async function main() { { let error = false; - writes = buildSteps.flatMap(fn => { - const fns = fn({wikiData}) || []; + const targets = buildSteps.flatMap(([ flag, pageSpec ]) => { + const targets = pageSpec.targets({wikiData}); + return targets.map(target => ({flag, pageSpec, target})); + }); + + const writeArrays = await progressPromiseAll(`Processing build data to be shared across langauges.`, queue( + targets.map(({ flag, pageSpec, target }) => () => { + const writes = pageSpec.write(target, {wikiData}) || []; + + // Do a quick valid8tion! If one of the writeThingPages functions go + // wrong, this will stall out early and tell us which did. + + if (!Array.isArray(writes)) { + logError`${flag + '.write'} didn't return an array!`; + error = true; + return []; + } - // Do a quick valid8tion! If one of the writeThingPages functions go - // wrong, this will stall out early and tell us which did. - if (!Array.isArray(fns)) { - logError`${fn.name} didn't return an array!`; - error = true; - } else if (fns.every(entry => Array.isArray(entry))) { if (!( - fns.every(entry => entry.every(obj => typeof obj === 'object')) && - fns.every(entry => entry.every(obj => { + writes.every(obj => typeof obj === 'object') && + writes.every(obj => { const result = validateWriteObject(obj); if (result.error) { logError`Validating write object failed: ${result.error}`; @@ -6370,24 +5937,23 @@ async function main() { } else { return true; } - })) + }) )) { - logError`${fn.name} uses updated format, but entries are invalid!`; + logError`${flag + '.write'} uses updated format, but entries are invalid!`; error = true; + return []; } - return fns.flatMap(writes => writes); - } else if (fns.some(fn => typeof fn !== 'function')) { - logError`${fn.name} didn't return all functions or all arrays!`; - error = true; - } - - return fns; - }); + return writes; + }), + queueSize + )); if (error) { return; } + + writes = writeArrays.flatMap(writes => writes); } const pageWrites = writes.filter(({ type }) => type === 'page'); @@ -6395,8 +5961,36 @@ async function main() { const redirectWrites = writes.filter(({ type }) => type === 'redirect'); await progressPromiseAll(`Writing data files shared across languages.`, queue( - // TODO: This only supports one <>-style argument. - dataWrites.map(({path, data}) => () => writeData(path[0], path[1], data())), + dataWrites.map(({path, data}) => () => { + const bound = {}; + + bound.serializeLink = bindOpts(serializeLink, {}); + + bound.serializeContribs = bindOpts(serializeContribs, {}); + + bound.serializeImagePaths = bindOpts(serializeImagePaths, { + thumb + }); + + bound.serializeCover = bindOpts(serializeCover, { + [bindOpts.bindIndex]: 2, + serializeImagePaths: bound.serializeImagePaths, + urls + }); + + bound.serializeGroupsForAlbum = bindOpts(serializeGroupsForAlbum, { + serializeLink + }); + + bound.serializeGroupsForTrack = bindOpts(serializeGroupsForTrack, { + serializeLink + }); + + // TODO: This only supports one <>-style argument. + return writeData(path[0], path[1], data({ + ...bound + })); + }), queueSize )); @@ -6453,6 +6047,10 @@ async function main() { to }); + bound.fancifyURL = bindOpts(fancifyURL, { + strings + }); + bound.getArtistString = bindOpts(getArtistString, { iconifyURL: bound.iconifyURL, link: bound.link, @@ -6471,6 +6069,12 @@ async function main() { to }); + bound.chronologyLinks = bindOpts(chronologyLinks, { + link: bound.link, + strings, + wikiData + }); + bound.generateCoverLink = bindOpts(generateCoverLink, { [bindOpts.bindIndex]: 0, link: bound.link, diff --git a/src/util/serialize.js b/src/util/serialize.js new file mode 100644 index 00000000..7b0f890f --- /dev/null +++ b/src/util/serialize.js @@ -0,0 +1,71 @@ +export function serializeLink(thing) { + const ret = {}; + ret.name = thing.name; + ret.directory = thing.directory; + if (thing.color) ret.color = thing.color; + return ret; +} + +export function serializeContribs(contribs) { + return contribs.map(({ who, what }) => { + const ret = {}; + ret.artist = serializeLink(who); + if (what) ret.contribution = what; + return ret; + }); +} + +export function serializeImagePaths(original, {thumb}) { + return { + original, + medium: thumb.medium(original), + small: thumb.small(original) + }; +} + +export function serializeCover(thing, pathFunction, { + serializeImagePaths, + urls +}) { + const coverPath = pathFunction(thing, { + to: urls.from('media.root').to + }); + + const { artTags } = thing; + + const cwTags = artTags.filter(tag => tag.isCW); + const linkTags = artTags.filter(tag => !tag.isCW); + + return { + paths: serializeImagePaths(coverPath), + tags: linkTags.map(serializeLink), + warnings: cwTags.map(tag => tag.name) + }; +} + +export function serializeGroupsForAlbum(album, { + serializeLink +}) { + return album.groups.map(group => { + const index = group.albums.indexOf(album); + const next = group.albums[index + 1] || null; + const previous = group.albums[index - 1] || null; + return {group, index, next, previous}; + }).map(({group, index, next, previous}) => ({ + link: serializeLink(group), + descriptionShort: group.descriptionShort, + albumIndex: index, + nextAlbum: next && serializeLink(next), + previousAlbum: previous && serializeLink(previous), + urls: group.urls + })); +} + +export function serializeGroupsForTrack(track, { + serializeLink +}) { + return track.album.groups.map(group => ({ + link: serializeLink(group), + urls: group.urls, + })); +} diff --git a/src/util/wiki-data.js b/src/util/wiki-data.js index e76722bd..13b86090 100644 --- a/src/util/wiki-data.js +++ b/src/util/wiki-data.js @@ -89,6 +89,15 @@ export function sortByArtDate(data) { // Specific data utilities +export function getAlbumCover(album, {to}) { + return to('media.albumCover', album.directory); +} + +export function getAlbumListTag(album) { + // TODO: This is hard-coded! No. 8ad. + return (album.directory === 'unreleased-tracks' ? 'ul' : 'ol'); +} + // This gets all the track o8jects defined in every al8um, and sorts them 8y // date released. Generally, albumData will pro8a8ly already 8e sorted 8efore // you pass it to this function, 8ut individual tracks can have their own @@ -124,3 +133,25 @@ export function getArtistCommentary(artist, {justEverythingMan}) { .replace(/<\/?b>/g, '') .includes('<i>' + artist.name + ':</i>'))); } + +export function getFlashCover(flash, {to}) { + return to('media.flashArt', flash.directory); +} + +export function getFlashLink(flash) { + return `https://homestuck.com/story/${flash.page}`; +} + +export function getTotalDuration(tracks) { + return tracks.reduce((duration, track) => duration + track.duration, 0); +} + +export function getTrackCover(track, {to}) { + // Some al8ums don't have any track art at all, and in those, every track + // just inherits the al8um's own cover art. + if (track.coverArtists === null) { + return getAlbumCover(track.album, {to}); + } else { + return to('media.trackCover', track.album.directory, track.directory); + } +} |