diff options
-rw-r--r-- | src/data/things.js | 74 | ||||
-rw-r--r-- | src/data/validators.js | 7 | ||||
-rw-r--r-- | src/misc-templates.js | 2 | ||||
-rw-r--r-- | src/page/album.js | 27 | ||||
-rw-r--r-- | src/page/track.js | 58 | ||||
-rwxr-xr-x | src/upd8.js | 13 | ||||
-rw-r--r-- | src/util/find.js | 31 |
7 files changed, 157 insertions, 55 deletions
diff --git a/src/data/things.js b/src/data/things.js index 4f4c2908..90d09b9c 100644 --- a/src/data/things.js +++ b/src/data/things.js @@ -20,6 +20,7 @@ import { isNumber, isURL, isString, + isWholeNumber, oneOf, validateArrayItems, validateInstanceOf, @@ -270,7 +271,7 @@ Thing.common = { expose: { dependencies: ['artistData', contribsByRefProperty], compute: ({ artistData, [contribsByRefProperty]: contribsByRef }) => ( - (contribsByRef && artistData + ((contribsByRef && artistData) ? (contribsByRef .map(({ who: ref, what }) => ({ who: find.artist(ref, {wikiData: {artistData}}), @@ -329,7 +330,10 @@ Thing.common = { dependencies: [wikiDataProperty], compute: ({ [wikiDataProperty]: wikiData, [Thing.instance]: thing }) => ( - wikiData?.filter(t => t[referencerRefListProperty]?.includes(thing))) + (wikiData + ? wikiData.filter(t => t[referencerRefListProperty]?.includes(thing)) + : []) + ) } }), @@ -466,7 +470,25 @@ TrackGroup.propertyDescriptors = { // Update & expose name: Thing.common.name('Unnamed Track Group'), - color: Thing.common.color(), + + color: { + flags: {update: true, expose: true}, + + update: {validate: isColor}, + + expose: { + dependencies: ['album'], + + transform(color, { album }) { + return color ?? album?.color ?? null; + } + } + }, + + startIndex: { + flags: {update: true, expose: true}, + update: {validate: isWholeNumber} + }, dateOriginallyReleased: Thing.common.simpleDate(), @@ -476,6 +498,11 @@ TrackGroup.propertyDescriptors = { // Update only + album: { + flags: {update: true}, + update: {validate: validateInstanceOf(Album)} + }, + trackData: Thing.common.wikiData(Track), // Expose only @@ -544,6 +571,7 @@ Track.propertyDescriptors = { albumData: Thing.common.wikiData(Album), artistData: Thing.common.wikiData(Artist), artTagData: Thing.common.wikiData(ArtTag), + flashData: Thing.common.wikiData(Flash), trackData: Thing.common.wikiData(Track), // Expose only @@ -565,12 +593,26 @@ Track.propertyDescriptors = { dependencies: ['albumData', 'dateFirstReleased'], compute: ({ albumData, dateFirstReleased, [Track.instance]: track }) => ( dateFirstReleased ?? - Track.findAlbum(track)?.date ?? + Track.findAlbum(track, albumData)?.date ?? null ) } }, + color: { + flags: {expose: true}, + + expose: { + dependencies: ['albumData', 'trackData'], + + compute: ({ albumData, trackData, [Track.instance]: track }) => ( + (Track.findAlbum(track, albumData)?.trackGroups + .find(tg => tg.tracks.includes(track))?.color) + ?? null + ) + } + }, + coverArtDate: { flags: {update: true, expose: true}, @@ -588,6 +630,30 @@ Track.propertyDescriptors = { } }, + otherReleases: { + flags: {expose: true}, + + expose: { + dependencies: ['originalReleaseTrackByRef', 'trackData'], + + compute: ({ originalReleaseTrackByRef: ref1, trackData, [Track.instance]: t1 }) => ( + (ref1 && trackData + ? [ + find.track(ref1, {wikiData: {trackData}}), + ...trackData.filter(t2 => { + const { originalReleaseTrackByRef: ref2 } = t2; + return ( + t2 !== t1 && + ref2 && + ( + find.track(ref2, {wikiData: {trackData}}) === + find.track(ref1, {wikiData: {trackData}}))) + })] + : []) + ) + } + }, + // Previously known as: (track).artists artistContribs: Thing.common.dynamicInheritContribs('artistContribsByRef', 'artistContribsByRef', 'albumData', Track.findAlbum), diff --git a/src/data/validators.js b/src/data/validators.js index 83922229..ca10833e 100644 --- a/src/data/validators.js +++ b/src/data/validators.js @@ -81,6 +81,13 @@ export function isCountingNumber(number) { return true; } +export function isWholeNumber(number) { + isInteger(number); + isPositiveOrZero(number); + + return true; +} + export function isString(value) { return isType(value, 'string'); } diff --git a/src/misc-templates.js b/src/misc-templates.js index 1fc05f0f..3ad1f233 100644 --- a/src/misc-templates.js +++ b/src/misc-templates.js @@ -35,7 +35,7 @@ export function getArtistString(artists, { return [ link.artist(who), showContrib && what && `(${what})`, - showIcons && urls.length && `<span class="icons">(${ + showIcons && urls?.length && `<span class="icons">(${ strings.list.unit(urls.map(url => iconifyURL(url, {strings}))) })</span>` ].filter(Boolean).join(' '); diff --git a/src/page/album.js b/src/page/album.js index 6e8d6dbc..1ebfdecc 100644 --- a/src/page/album.js +++ b/src/page/album.js @@ -164,9 +164,11 @@ export function write(album, {wikiData}) { strings('releaseInfo.released', { date: strings.count.date(album.date) }), - +album.coverArtDate !== +album.date && strings('releaseInfo.artReleased', { - date: strings.count.date(album.coverArtDate) - }), + (album.coverArtDate && + +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}) }) @@ -179,7 +181,7 @@ export function write(album, {wikiData}) { }) }) }</p>`} - ${album.urls.length && `<p>${ + ${album.urls?.length && `<p>${ strings('releaseInfo.listenOn', { links: strings.list.or(album.urls.map(url => fancifyURL(url, {album: true}))) }) @@ -263,12 +265,16 @@ export function generateAlbumSidebar(album, currentTrack, { }) { const listTag = getAlbumListTag(album); + /* const trackGroups = album.trackGroups || [{ name: strings('albumSidebar.trackList.fallbackGroupName'), color: album.color, startIndex: 0, tracks: album.tracks }]; + */ + + const { trackGroups } = album; const trackToListItem = track => html.tag('li', {class: track === currentTrack && 'current'}, @@ -276,9 +282,14 @@ export function generateAlbumSidebar(album, currentTrack, { track: link.track(track) })); + const nameOrDefault = (isDefaultTrackGroup, name) => + (isDefaultTrackGroup + ? strings('albumSidebar.trackList.fallbackGroupName') + : name); + const trackListPart = fixWS` <h1>${link.album(album)}</h1> - ${trackGroups.map(({ name, color, startIndex, tracks }) => + ${trackGroups.map(({ name, color, startIndex, tracks, isDefaultTrackGroup }) => html.tag('details', { // Leave side8ar track groups collapsed on al8um homepage, // since there's already a view of all the groups expanded @@ -290,11 +301,11 @@ export function generateAlbumSidebar(album, currentTrack, { {style: getLinkThemeString(color)}, (listTag === 'ol' ? strings('albumSidebar.trackList.group.withRange', { - group: `<span class="group-name">${name}</span>`, + group: `<span class="group-name">${nameOrDefault(isDefaultTrackGroup, name)}</span>`, range: `${startIndex + 1}–${startIndex + tracks.length}` }) : strings('albumSidebar.trackList.group', { - group: `<span class="group-name">${name}</span>` + group: `<span class="group-name">${nameOrDefault(isDefaultTrackGroup, name)}</span>` })) ), fixWS` @@ -319,7 +330,7 @@ export function generateAlbumSidebar(album, currentTrack, { }) }</h1> ${!currentTrack && transformMultiline(group.descriptionShort)} - ${group.urls.length && `<p>${ + ${group.urls?.length && `<p>${ strings('releaseInfo.visitOn', { links: strings.list.or(group.urls.map(url => fancifyURL(url))) }) diff --git a/src/page/track.js b/src/page/track.js index b3cec414..a6ec722e 100644 --- a/src/page/track.js +++ b/src/page/track.js @@ -35,23 +35,20 @@ export function targets({wikiData}) { export function write(track, {wikiData}) { const { groupData, wikiInfo } = wikiData; - const { album } = track; + const { album, referencedByTracks, referencedTracks, otherReleases } = track; - const tracksThatReference = track.referencedBy; const useDividedReferences = groupData.some(group => group.directory === OFFICIAL_GROUP_DIRECTORY); - const ttrFanon = (useDividedReferences && - tracksThatReference.filter(t => t.album.groups.every(group => group.directory !== OFFICIAL_GROUP_DIRECTORY))); - const ttrOfficial = (useDividedReferences && - tracksThatReference.filter(t => t.album.groups.some(group => group.directory === OFFICIAL_GROUP_DIRECTORY))); + const rbtFanon = (useDividedReferences && + referencedByTracks.filter(t => t.album.groups.every(group => group.directory !== OFFICIAL_GROUP_DIRECTORY))); + const rbtOfficial = (useDividedReferences && + referencedByTracks.filter(t => t.album.groups.some(group => group.directory === OFFICIAL_GROUP_DIRECTORY))); - const tracksReferenced = track.references; - const otherReleases = track.otherReleases; const listTag = getAlbumListTag(album); let flashesThatFeature; if (wikiInfo.enableFlashesAndGames) { flashesThatFeature = sortByDate([track, ...otherReleases] - .flatMap(track => track.flashes.map(flash => ({flash, as: track})))); + .flatMap(track => track.featuredInFlashes.map(flash => ({flash, as: track})))); } const unbound_generateTrackList = (tracks, {getArtistString, link, strings}) => html.tag('ul', @@ -59,7 +56,7 @@ export function write(track, {wikiData}) { const line = strings('trackList.item.withArtists', { track: link.track(track), by: `<span class="by">${strings('trackList.item.withArtists.by', { - artists: getArtistString(track.artists) + artists: getArtistString(track.artistContribs) })}</span>` }); return (track.aka @@ -172,13 +169,13 @@ export function write(track, {wikiData}) { <p> ${[ strings('releaseInfo.by', { - artists: getArtistString(track.artists, { + artists: getArtistString(track.artistContribs, { showContrib: true, showIcons: true }) }), track.coverArtists && strings('releaseInfo.coverArtBy', { - artists: getArtistString(track.coverArtists, { + artists: getArtistString(track.coverArtistContribs, { showContrib: true, showIcons: true }) @@ -186,16 +183,18 @@ export function write(track, {wikiData}) { album.directory !== UNRELEASED_TRACKS_DIRECTORY && strings('releaseInfo.released', { date: strings.count.date(track.date) }), - +track.coverArtDate !== +track.date && strings('releaseInfo.artReleased', { - date: strings.count.date(track.coverArtDate) - }), + (track.coverArtDate && + +track.coverArtDate !== +track.date && + strings('releaseInfo.artReleased', { + date: strings.count.date(track.coverArtDate) + })), track.duration && strings('releaseInfo.duration', { duration: strings.count.duration(track.duration) }) ].filter(Boolean).join('<br>\n')} </p> <p>${ - (track.urls.length + (track.urls?.length ? strings('releaseInfo.listenOn', { links: strings.list.or(track.urls.map(url => fancifyURL(url, {strings}))) }) @@ -212,17 +211,10 @@ export function write(track, {wikiData}) { `).join('\n')} </ul> `} - ${track.contributors.textContent && fixWS` - <p> - ${strings('releaseInfo.contributors')} - <br> - ${transformInline(track.contributors.textContent)} - </p> - `} - ${track.contributors.length && fixWS` + ${track.contributorContribs.length && fixWS` <p>${strings('releaseInfo.contributors')}</p> <ul> - ${(track.contributors + ${(track.contributorContribs .map(contrib => `<li>${getArtistString([contrib], { showContrib: true, showIcons: true @@ -230,25 +222,25 @@ export function write(track, {wikiData}) { .join('\n'))} </ul> `} - ${tracksReferenced.length && fixWS` + ${referencedTracks.length && fixWS` <p>${strings('releaseInfo.tracksReferenced', {track: `<i>${track.name}</i>`})}</p> - ${generateTrackList(tracksReferenced)} + ${generateTrackList(referencedTracks)} `} - ${tracksThatReference.length && fixWS` + ${referencedByTracks.length && fixWS` <p>${strings('releaseInfo.tracksThatReference', {track: `<i>${track.name}</i>`})}</p> ${useDividedReferences && fixWS` <dl> - ${ttrOfficial.length && fixWS` + ${rbtOfficial.length && fixWS` <dt>${strings('trackPage.referenceList.official')}</dt> - <dd>${generateTrackList(ttrOfficial)}</dd> + <dd>${generateTrackList(rbtOfficial)}</dd> `} - ${ttrFanon.length && fixWS` + ${rbtFanon.length && fixWS` <dt>${strings('trackPage.referenceList.fandom')}</dt> - <dd>${generateTrackList(ttrFanon)}</dd> + <dd>${generateTrackList(rbtFanon)}</dd> `} </dl> `} - ${!useDividedReferences && generateTrackList(tracksThatReference)} + ${!useDividedReferences && generateTrackList(referencedByTracks)} `} ${wikiInfo.enableFlashesAndGames && flashesThatFeature.length && fixWS` <p>${strings('releaseInfo.flashesThatFeature', {track: `<i>${track.name}</i>`})}</p> diff --git a/src/upd8.js b/src/upd8.js index 2769d42a..70aec6c8 100755 --- a/src/upd8.js +++ b/src/upd8.js @@ -906,6 +906,8 @@ function processAlbumEntryDocuments(documents) { let currentTracksByRef = null; let currentTrackGroupDoc = null; + let trackIndex = 0; + function closeCurrentTrackGroup() { if (currentTracksByRef) { let trackGroup; @@ -917,6 +919,7 @@ function processAlbumEntryDocuments(documents) { trackGroup.isDefaultTrackGroup = true; } + trackGroup.startIndex = trackIndex; trackGroup.tracksByRef = currentTracksByRef; trackGroups.push(trackGroup); } @@ -930,6 +933,8 @@ function processAlbumEntryDocuments(documents) { continue; } + trackIndex++; + const track = processTrackDocument(doc); tracks.push(track); @@ -2384,6 +2389,7 @@ async function main() { trackGroup.isDefaultTrackGroup = true; } + trackGroup.album = album; trackGroup.tracksByRef = currentTracksByRef; trackGroups.push(trackGroup); } @@ -2773,7 +2779,6 @@ async function main() { return; } - // Data linking! Basically, provide (portions of) wikiData to the Things // which require it - they'll expose dynamically computed properties as a // result (many of which are required for page HTML generation). @@ -2792,6 +2797,7 @@ async function main() { track.albumData = WD.albumData; track.artistData = WD.artistData; track.artTagData = WD.artTagData; + track.flashData = WD.flashData; track.trackData = WD.trackData; } @@ -2815,7 +2821,8 @@ async function main() { trackData: sortByDate(WD.trackData.slice()) }); - // console.log(WD.trackData.find(t => t.name === 'Aggrievance').artTags[0].taggedInThings.map(thing => thing.name)); + // const track = WD.trackData.find(t => t.name === 'Under the Sun'); + // console.log(track.album.trackGroups.find(tg => tg.tracks.includes(track)).color, track.color); // return; // Update languages o8ject with the wiki-specified default language! @@ -3163,7 +3170,7 @@ async function main() { return true; }; - return; + // return; writes = buildStepsWithTargets.flatMap(({ flag, pageSpec, targets }) => { const writes = targets.flatMap(target => diff --git a/src/util/find.js b/src/util/find.js index 872b3b7a..e8e04a5b 100644 --- a/src/util/find.js +++ b/src/util/find.js @@ -4,6 +4,12 @@ import { } from './cli.js'; function findHelper(keys, dataProp, findFns = {}) { + // Note: This cache explicitly *doesn't* support mutable data arrays. If the + // data array is modified, make sure it's actually a new array object, not + // the original, or the cache here will break and act as though the data + // hasn't changed! + const cache = new WeakMap(); + const byDirectory = findFns.byDirectory || matchDirectory; const byName = findFns.byName || matchName; @@ -15,6 +21,23 @@ function findHelper(keys, dataProp, findFns = {}) { throw new Error(`Got a reference that is ${typeof fullRef}, not string: ${fullRef}`); } + const data = wikiData[dataProp]; + + if (!data) { + throw new Error(`Expected data to be present`); + } + + let cacheForThisData = cache.get(data); + const cachedValue = cacheForThisData?.[fullRef]; + if (cachedValue) { + globalThis.NUM_CACHE = (globalThis.NUM_CACHE || 0) + 1; + return cachedValue; + } + if (!cacheForThisData) { + cacheForThisData = Object.create(null); + cache.set(data, cacheForThisData); + } + const match = fullRef.match(keyRefRegex); if (!match) { throw new Error(`Malformed link reference: "${fullRef}"`); @@ -23,12 +46,6 @@ function findHelper(keys, dataProp, findFns = {}) { const key = match[1]; const ref = match[2]; - const data = wikiData[dataProp]; - - if (!data) { - throw new Error(`Expected data to be present`); - } - const found = (key ? byDirectory(ref, data, quiet) : byName(ref, data, quiet)); @@ -37,6 +54,8 @@ function findHelper(keys, dataProp, findFns = {}) { logWarn`Didn't match anything for ${fullRef}!`; } + cacheForThisData[fullRef] = found; + return found; }; } |