diff options
Diffstat (limited to 'src/listing-spec.js')
-rw-r--r-- | src/listing-spec.js | 1111 |
1 files changed, 302 insertions, 809 deletions
diff --git a/src/listing-spec.js b/src/listing-spec.js index c5b9429..73fbee6 100644 --- a/src/listing-spec.js +++ b/src/listing-spec.js @@ -1,819 +1,312 @@ -import fixWS from 'fix-whitespace'; - -import { - UNRELEASED_TRACKS_DIRECTORY -} from './util/magic-constants.js'; - -import { - chunkByProperties, - getArtistNumContributions, - getTotalDuration, - sortByDate, - sortByName -} from './util/wiki-data.js'; - -const listingSpec = [ - { - directory: 'albums/by-name', - stringsKey: 'listAlbums.byName', - - data({wikiData}) { - return wikiData.albumData.slice() - .sort(sortByName); - }, - - row(album, {link, strings}) { - return strings('listingPage.listAlbums.byName.item', { - album: link.album(album), - tracks: strings.count.tracks(album.tracks.length, {unit: true}) - }); +import {showAggregate} from '#aggregate'; +import {empty} from '#sugar'; + +const listingSpec = []; + +listingSpec.push({ + directory: 'albums/by-name', + stringsKey: 'listAlbums.byName', + contentFunction: 'listAlbumsByName', + + seeAlso: [ + 'tracks/by-album', + ], +}); + +listingSpec.push({ + directory: 'albums/by-tracks', + stringsKey: 'listAlbums.byTracks', + contentFunction: 'listAlbumsByTracks', +}); + +listingSpec.push({ + directory: 'albums/by-duration', + stringsKey: 'listAlbums.byDuration', + contentFunction: 'listAlbumsByDuration', +}); + +listingSpec.push({ + directory: 'albums/by-date', + stringsKey: 'listAlbums.byDate', + contentFunction: 'listAlbumsByDate', + + seeAlso: [ + 'tracks/by-date', + ], +}); + +listingSpec.push({ + directory: 'albums/by-date-added', + stringsKey: 'listAlbums.byDateAdded', + contentFunction: 'listAlbumsByDateAdded', +}); + +listingSpec.push({ + directory: 'artists/by-name', + stringsKey: 'listArtists.byName', + contentFunction: 'listArtistsByName', + seeAlso: ['artists/by-contribs', 'artists/by-group'], +}); + +listingSpec.push({ + directory: 'artists/by-contribs', + stringsKey: 'listArtists.byContribs', + contentFunction: 'listArtistsByContributions', + seeAlso: ['artists/by-name', 'artists/by-group'], +}); + +listingSpec.push({ + directory: 'artists/by-commentary', + stringsKey: 'listArtists.byCommentary', + contentFunction: 'listArtistsByCommentaryEntries', +}); + +listingSpec.push({ + directory: 'artists/by-duration', + stringsKey: 'listArtists.byDuration', + contentFunction: 'listArtistsByDuration', +}); + +// TODO: hide if no groups... +listingSpec.push({ + directory: 'artists/by-group', + stringsKey: 'listArtists.byGroup', + contentFunction: 'listArtistsByGroup', + featureFlag: 'enableGroupUI', + seeAlso: ['artists/by-name', 'artists/by-contribs'], +}); + +listingSpec.push({ + directory: 'artists/by-latest', + stringsKey: 'listArtists.byLatest', + contentFunction: 'listArtistsByLatestContribution', +}); + +listingSpec.push({ + directory: 'groups/by-name', + stringsKey: 'listGroups.byName', + contentFunction: 'listGroupsByName', + featureFlag: 'enableGroupUI', +}); + +listingSpec.push({ + directory: 'groups/by-category', + stringsKey: 'listGroups.byCategory', + contentFunction: 'listGroupsByCategory', + featureFlag: 'enableGroupUI', +}); + +listingSpec.push({ + directory: 'groups/by-albums', + stringsKey: 'listGroups.byAlbums', + contentFunction: 'listGroupsByAlbums', + featureFlag: 'enableGroupUI', +}); + +listingSpec.push({ + directory: 'groups/by-tracks', + stringsKey: 'listGroups.byTracks', + contentFunction: 'listGroupsByTracks', + featureFlag: 'enableGroupUI', +}); + +listingSpec.push({ + directory: 'groups/by-duration', + stringsKey: 'listGroups.byDuration', + contentFunction: 'listGroupsByDuration', + featureFlag: 'enableGroupUI', +}); + +listingSpec.push({ + directory: 'groups/by-latest-album', + stringsKey: 'listGroups.byLatest', + contentFunction: 'listGroupsByLatestAlbum', + featureFlag: 'enableGroupUI', +}); + +listingSpec.push({ + directory: 'tracks/by-name', + stringsKey: 'listTracks.byName', + contentFunction: 'listTracksByName', +}); + +listingSpec.push({ + directory: 'tracks/by-album', + stringsKey: 'listTracks.byAlbum', + contentFunction: 'listTracksByAlbum', +}); + +listingSpec.push({ + directory: 'tracks/by-date', + stringsKey: 'listTracks.byDate', + contentFunction: 'listTracksByDate', +}); + +listingSpec.push({ + directory: 'tracks/by-duration', + stringsKey: 'listTracks.byDuration', + contentFunction: 'listTracksByDuration', +}); + +listingSpec.push({ + directory: 'tracks/by-duration-in-album', + stringsKey: 'listTracks.byDurationInAlbum', + contentFunction: 'listTracksByDurationInAlbum', +}); + +listingSpec.push({ + directory: 'tracks/by-times-referenced', + stringsKey: 'listTracks.byTimesReferenced', + contentFunction: 'listTracksByTimesReferenced', +}); + +listingSpec.push({ + directory: 'tracks/in-flashes/by-album', + stringsKey: 'listTracks.inFlashes.byAlbum', + contentFunction: 'listTracksInFlashesByAlbum', + featureFlag: 'enableFlashesAndGames', +}); + +listingSpec.push({ + directory: 'tracks/in-flashes/by-flash', + stringsKey: 'listTracks.inFlashes.byFlash', + contentFunction: 'listTracksInFlashesByFlash', + featureFlag: 'enableFlashesAndGames', +}); + +listingSpec.push({ + directory: 'tracks/with-lyrics', + stringsKey: 'listTracks.withLyrics', + contentFunction: 'listTracksWithLyrics', +}); + +listingSpec.push({ + directory: 'tracks/with-sheet-music-files', + stringsKey: 'listTracks.withSheetMusicFiles', + contentFunction: 'listTracksWithSheetMusicFiles', + seeAlso: ['all-sheet-music-files'], +}); + +listingSpec.push({ + directory: 'tracks/with-midi-project-files', + stringsKey: 'listTracks.withMidiProjectFiles', + contentFunction: 'listTracksWithMidiProjectFiles', + seeAlso: ['all-midi-project-files'], +}); + +listingSpec.push({ + directory: 'tags/by-name', + stringsKey: 'listTags.byName', + contentFunction: 'listTagsByName', + featureFlag: 'enableArtTagUI', +}); + +listingSpec.push({ + directory: 'tags/by-uses', + stringsKey: 'listTags.byUses', + contentFunction: 'listTagsByUses', + featureFlag: 'enableArtTagUI', +}); + +listingSpec.push({ + directory: 'all-sheet-music-files', + stringsKey: 'other.allSheetMusic', + contentFunction: 'listAllSheetMusicFiles', + seeAlso: ['tracks/with-sheet-music-files'], + groupUnderOther: true, +}); + +listingSpec.push({ + directory: 'all-midi-project-files', + stringsKey: 'other.allMidiProjectFiles', + contentFunction: 'listAllMidiProjectFiles', + seeAlso: ['tracks/with-midi-project-files'], + groupUnderOther: true, +}); + +listingSpec.push({ + directory: 'all-additional-files', + stringsKey: 'other.allAdditionalFiles', + contentFunction: 'listAllAdditionalFiles', + groupUnderOther: true, +}); + +listingSpec.push({ + directory: 'random', + stringsKey: 'other.randomPages', + contentFunction: 'listRandomPageLinks', + groupUnderOther: true, +}); + +{ + const errors = []; + + for (const listing of listingSpec) { + if (listing.seeAlso) { + const suberrors = []; + + for (let i = 0; i < listing.seeAlso.length; i++) { + const directory = listing.seeAlso[i]; + const match = listingSpec.find(listing => listing.directory === directory); + + if (match) { + listing.seeAlso[i] = match; + } else { + listing.seeAlso[i] = null; + suberrors.push(new Error(`(index: ${i}) Didn't find a listing matching ${directory}`)) } - }, - - { - directory: 'albums/by-tracks', - stringsKey: 'listAlbums.byTracks', - - data({wikiData}) { - return wikiData.albumData.slice() - .sort((a, b) => b.tracks.length - a.tracks.length); - }, - - row(album, {link, strings}) { - return strings('listingPage.listAlbums.byTracks.item', { - album: link.album(album), - tracks: strings.count.tracks(album.tracks.length, {unit: true}) - }); - } - }, - - { - directory: 'albums/by-duration', - stringsKey: 'listAlbums.byDuration', - - data({wikiData}) { - return wikiData.albumData - .map(album => ({album, duration: getTotalDuration(album.tracks)})) - .sort((a, b) => b.duration - a.duration); - }, - - row({album, duration}, {link, strings}) { - return strings('listingPage.listAlbums.byDuration.item', { - album: link.album(album), - duration: strings.count.duration(duration) - }); - } - }, - - { - directory: 'albums/by-date', - stringsKey: 'listAlbums.byDate', - - data({wikiData}) { - return sortByDate(wikiData.albumData - .filter(album => album.directory !== UNRELEASED_TRACKS_DIRECTORY)); - }, - - row(album, {link, strings}) { - return strings('listingPage.listAlbums.byDate.item', { - album: link.album(album), - date: strings.count.date(album.date) - }); - } - }, - - { - directory: 'albusm/by-date-added', - stringsKey: 'listAlbums.byDateAdded', - - data({wikiData}) { - return chunkByProperties(wikiData.albumData.slice().sort((a, b) => { - if (a.dateAdded < b.dateAdded) return -1; - if (a.dateAdded > b.dateAdded) return 1; - }), ['dateAdded']); - }, - - html(chunks, {link, strings}) { - return fixWS` - <dl> - ${chunks.map(({dateAdded, chunk: albums}) => fixWS` - <dt>${strings('listingPage.listAlbums.byDateAdded.date', { - date: strings.count.date(dateAdded) - })}</dt> - <dd><ul> - ${(albums - .map(album => strings('listingPage.listAlbums.byDateAdded.album', { - album: link.album(album) - })) - .map(row => `<li>${row}</li>`) - .join('\n'))} - </ul></dd> - `).join('\n')} - </dl> - `; - } - }, - - { - directory: 'artists/by-name', - stringsKey: 'listArtists.byName', - - data({wikiData}) { - return wikiData.artistData.slice() - .sort(sortByName) - .map(artist => ({artist, contributions: getArtistNumContributions(artist)})); - }, - - row({artist, contributions}, {link, strings}) { - return strings('listingPage.listArtists.byName.item', { - artist: link.artist(artist), - contributions: strings.count.contributions(contributions, {unit: true}) - }); - } - }, - - { - directory: 'artists/by-contribs', - stringsKey: 'listArtists.byContribs', - - data({wikiData}) { - return { - toTracks: (wikiData.artistData - .map(artist => ({ - artist, - contributions: ( - artist.tracks.asContributor.length + - artist.tracks.asArtist.length - ) - })) - .sort((a, b) => b.contributions - a.contributions) - .filter(({ contributions }) => contributions)), - - toArtAndFlashes: (wikiData.artistData - .map(artist => ({ - artist, - contributions: ( - artist.tracks.asCoverArtist.length + - artist.albums.asCoverArtist.length + - artist.albums.asWallpaperArtist.length + - artist.albums.asBannerArtist.length + - (wikiData.wikiInfo.features.flashesAndGames - ? artist.flashes.asContributor.length - : 0) - ) - })) - .sort((a, b) => b.contributions - a.contributions) - .filter(({ contributions }) => contributions)), - - // This is a kinda naughty hack, 8ut like, it's the only place - // we'd 8e passing wikiData to html() otherwise, so like.... - // (Ok we do do this again once later.) - showAsFlashes: wikiData.wikiInfo.features.flashesAndGames - }; - }, - - html({toTracks, toArtAndFlashes, showAsFlashes}, {link, strings}) { - return fixWS` - <div class="content-columns"> - <div class="column"> - <h2>${strings('listingPage.misc.trackContributors')}</h2> - <ul> - ${(toTracks - .map(({ artist, contributions }) => strings('listingPage.listArtists.byContribs.item', { - artist: link.artist(artist), - contributions: strings.count.contributions(contributions, {unit: true}) - })) - .map(row => `<li>${row}</li>`) - .join('\n'))} - </ul> - </div> - <div class="column"> - <h2>${strings('listingPage.misc' + - (showAsFlashes - ? '.artAndFlashContributors' - : '.artContributors'))}</h2> - <ul> - ${(toArtAndFlashes - .map(({ artist, contributions }) => strings('listingPage.listArtists.byContribs.item', { - artist: link.artist(artist), - contributions: strings.count.contributions(contributions, {unit: true}) - })) - .map(row => `<li>${row}</li>`) - .join('\n'))} - </ul> - </div> - </div> - `; - } - }, - - { - directory: 'artists/by-commentary', - stringsKey: 'listArtists.byCommentary', - - data({wikiData}) { - return wikiData.artistData - .map(artist => ({artist, entries: artist.tracks.asCommentator.length + artist.albums.asCommentator.length})) - .filter(({ entries }) => entries) - .sort((a, b) => b.entries - a.entries); - }, - - row({artist, entries}, {link, strings}) { - return strings('listingPage.listArtists.byCommentary.item', { - artist: link.artist(artist), - entries: strings.count.commentaryEntries(entries, {unit: true}) - }); - } - }, - - { - directory: 'artists/by-duration', - stringsKey: 'listArtists.byDuration', - - data({wikiData}) { - return wikiData.artistData - .map(artist => ({artist, duration: getTotalDuration( - [...artist.tracks.asArtist, ...artist.tracks.asContributor].filter(track => track.album.directory !== UNRELEASED_TRACKS_DIRECTORY)) - })) - .filter(({ duration }) => duration > 0) - .sort((a, b) => b.duration - a.duration); - }, - - row({artist, duration}, {link, strings}) { - return strings('listingPage.listArtists.byDuration.item', { - artist: link.artist(artist), - duration: strings.count.duration(duration) - }); - } - }, - - { - directory: 'artists/by-latest', - stringsKey: 'listArtists.byLatest', - - data({wikiData}) { - const reversedTracks = wikiData.trackData.slice().reverse(); - const reversedArtThings = wikiData.justEverythingSortedByArtDateMan.slice().reverse(); - - return { - toTracks: sortByDate(wikiData.artistData - .filter(artist => !artist.alias) - .map(artist => ({ - artist, - date: reversedTracks.find(({ album, artists, contributors }) => ( - album.directory !== UNRELEASED_TRACKS_DIRECTORY && - [...artists, ...contributors].some(({ who }) => who === artist) - ))?.date - })) - .filter(({ date }) => date) - .sort((a, b) => a.name < b.name ? 1 : a.name > b.name ? -1 : 0)).reverse(), - - toArtAndFlashes: sortByDate(wikiData.artistData - .filter(artist => !artist.alias) - .map(artist => { - const thing = reversedArtThings.find(({ album, coverArtists, contributors }) => ( - album?.directory !== UNRELEASED_TRACKS_DIRECTORY && - [...coverArtists || [], ...!album && contributors || []].some(({ who }) => who === artist) - )); - return thing && { - artist, - date: (thing.coverArtists?.some(({ who }) => who === artist) - ? thing.coverArtDate - : thing.date) - }; - }) - .filter(Boolean) - .sort((a, b) => a.name < b.name ? 1 : a.name > b.name ? -1 : 0) - ).reverse(), - - // (Ok we did it again.) - // This is a kinda naughty hack, 8ut like, it's the only place - // we'd 8e passing wikiData to html() otherwise, so like.... - showAsFlashes: wikiData.wikiInfo.features.flashesAndGames - }; - }, - - html({toTracks, toArtAndFlashes, showAsFlashes}, {link, strings}) { - return fixWS` - <div class="content-columns"> - <div class="column"> - <h2>${strings('listingPage.misc.trackContributors')}</h2> - <ul> - ${(toTracks - .map(({ artist, date }) => strings('listingPage.listArtists.byLatest.item', { - artist: link.artist(artist), - date: strings.count.date(date) - })) - .map(row => `<li>${row}</li>`) - .join('\n'))} - </ul> - </div> - <div class="column"> - <h2>${strings('listingPage.misc' + - (showAsFlashes - ? '.artAndFlashContributors' - : '.artContributors'))}</h2> - <ul> - ${(toArtAndFlashes - .map(({ artist, date }) => strings('listingPage.listArtists.byLatest.item', { - artist: link.artist(artist), - date: strings.count.date(date) - })) - .map(row => `<li>${row}</li>`) - .join('\n'))} - </ul> - </div> - </div> - `; - } - }, - - { - directory: 'groups/by-name', - stringsKey: 'listGroups.byName', - condition: ({wikiData}) => wikiData.wikiInfo.features.groupUI, - data: ({wikiData}) => wikiData.groupData.slice().sort(sortByName), - - row(group, {link, strings}) { - return strings('listingPage.listGroups.byCategory.group', { - group: link.groupInfo(group), - gallery: link.groupGallery(group, { - text: strings('listingPage.listGroups.byCategory.group.gallery') - }) - }); - } - }, - - { - directory: 'groups/by-category', - stringsKey: 'listGroups.byCategory', - condition: ({wikiData}) => wikiData.wikiInfo.features.groupUI, - data: ({wikiData}) => wikiData.groupCategoryData, - - html(groupCategoryData, {link, strings}) { - return fixWS` - <dl> - ${groupCategoryData.map(category => fixWS` - <dt>${strings('listingPage.listGroups.byCategory.category', { - category: link.groupInfo(category.groups[0], {text: category.name}) - })}</dt> - <dd><ul> - ${(category.groups - .map(group => strings('listingPage.listGroups.byCategory.group', { - group: link.groupInfo(group), - gallery: link.groupGallery(group, { - text: strings('listingPage.listGroups.byCategory.group.gallery') - }) - })) - .map(row => `<li>${row}</li>`) - .join('\n'))} - </ul></dd> - `).join('\n')} - </dl> - `; - } - }, - - { - directory: 'groups/by-albums', - stringsKey: 'listGroups.byAlbums', - condition: ({wikiData}) => wikiData.wikiInfo.features.groupUI, - - data({wikiData}) { - return wikiData.groupData - .map(group => ({group, albums: group.albums.length})) - .sort((a, b) => b.albums - a.albums); - }, - - row({group, albums}, {link, strings}) { - return strings('listingPage.listGroups.byAlbums.item', { - group: link.groupInfo(group), - albums: strings.count.albums(albums, {unit: true}) - }); - } - }, - - { - directory: 'groups/by-tracks', - stringsKey: 'listGroups.byTracks', - condition: ({wikiData}) => wikiData.wikiInfo.features.groupUI, - - data({wikiData}) { - return wikiData.groupData - .map(group => ({group, tracks: group.albums.reduce((acc, album) => acc + album.tracks.length, 0)})) - .sort((a, b) => b.tracks - a.tracks); - }, - - row({group, tracks}, {link, strings}) { - return strings('listingPage.listGroups.byTracks.item', { - group: link.groupInfo(group), - tracks: strings.count.tracks(tracks, {unit: true}) - }); - } - }, - - { - directory: 'groups/by-duration', - stringsKey: 'listGroups.byDuration', - condition: ({wikiData}) => wikiData.wikiInfo.features.groupUI, - - data({wikiData}) { - return wikiData.groupData - .map(group => ({group, duration: getTotalDuration(group.albums.flatMap(album => album.tracks))})) - .sort((a, b) => b.duration - a.duration); - }, - - row({group, duration}, {link, strings}) { - return strings('listingPage.listGroups.byDuration.item', { - group: link.groupInfo(group), - duration: strings.count.duration(duration) - }); - } - }, - - { - directory: 'groups/by-latest-album', - stringsKey: 'listGroups.byLatest', - condition: ({wikiData}) => wikiData.wikiInfo.features.groupUI, - - data({wikiData}) { - return sortByDate(wikiData.groupData - .map(group => ({group, date: group.albums[group.albums.length - 1].date})) - // So this is kinda tough to explain, 8ut 8asically, when we - // reverse the list after sorting it 8y d8te (so that the latest - // d8tes come first), it also flips the order of groups which - // share the same d8te. This happens mostly when a single al8um - // is the l8test in two groups. So, say one such al8um is in the - // groups "Fandom" and "UMSPAF". Per category order, Fandom is - // meant to show up 8efore UMSPAF, 8ut when we do the reverse - // l8ter, that flips them, and UMSPAF ends up displaying 8efore - // Fandom. So we do an extra reverse here, which will fix that - // and only affect groups that share the same d8te (8ecause - // groups that don't will 8e moved 8y the sortByDate call - // surrounding this). - .reverse()).reverse() - }, - - row({group, date}, {link, strings}) { - return strings('listingPage.listGroups.byLatest.item', { - group: link.groupInfo(group), - date: strings.count.date(date) - }); - } - }, - - { - directory: 'tracks/by-name', - stringsKey: 'listTracks.byName', + } - data({wikiData}) { - return wikiData.trackData.slice().sort(sortByName); - }, + listing.seeAlso = listing.seeAlso.filter(Boolean); - row(track, {link, strings}) { - return strings('listingPage.listTracks.byName.item', { - track: link.track(track) - }); - } - }, - - { - directory: 'tracks/by-album', - stringsKey: 'listTracks.byAlbum', - data: ({wikiData}) => wikiData.albumData, - - html(albumData, {link, strings}) { - return fixWS` - <dl> - ${albumData.map(album => fixWS` - <dt>${strings('listingPage.listTracks.byAlbum.album', { - album: link.album(album) - })}</dt> - <dd><ol> - ${(album.tracks - .map(track => strings('listingPage.listTracks.byAlbum.track', { - track: link.track(track) - })) - .map(row => `<li>${row}</li>`) - .join('\n'))} - </ol></dd> - `).join('\n')} - </dl> - `; - } - }, - - { - directory: 'tracks/by-date', - stringsKey: 'listTracks.byDate', - - data({wikiData}) { - return chunkByProperties( - sortByDate(wikiData.trackData.filter(track => track.album.directory !== UNRELEASED_TRACKS_DIRECTORY)), - ['album', 'date'] - ); - }, - - html(chunks, {link, strings}) { - return fixWS` - <dl> - ${chunks.map(({album, date, chunk: tracks}) => fixWS` - <dt>${strings('listingPage.listTracks.byDate.album', { - album: link.album(album), - date: strings.count.date(date) - })}</dt> - <dd><ul> - ${(tracks - .map(track => track.aka - ? `<li class="rerelease">${strings('listingPage.listTracks.byDate.track.rerelease', { - track: link.track(track) - })}</li>` - : `<li>${strings('listingPage.listTracks.byDate.track', { - track: link.track(track) - })}</li>`) - .join('\n'))} - </ul></dd> - `).join('\n')} - </dl> - `; - } - }, - - { - directory: 'tracks/by-duration', - stringsKey: 'listTracks.byDuration', - - data({wikiData}) { - return wikiData.trackData - .filter(track => track.album.directory !== UNRELEASED_TRACKS_DIRECTORY) - .map(track => ({track, duration: track.duration})) - .filter(({ duration }) => duration > 0) - .sort((a, b) => b.duration - a.duration); - }, - - row({track, duration}, {link, strings}) { - return strings('listingPage.listTracks.byDuration.item', { - track: link.track(track), - duration: strings.count.duration(duration) - }); - } - }, - - { - directory: 'tracks/by-duration-in-album', - stringsKey: 'listTracks.byDurationInAlbum', - - data({wikiData}) { - return wikiData.albumData.map(album => ({ - album, - tracks: album.tracks.slice().sort((a, b) => b.duration - a.duration) - })); - }, - - html(albums, {link, strings}) { - return fixWS` - <dl> - ${albums.map(({album, tracks}) => fixWS` - <dt>${strings('listingPage.listTracks.byDurationInAlbum.album', { - album: link.album(album) - })}</dt> - <dd><ul> - ${(tracks - .map(track => strings('listingPage.listTracks.byDurationInAlbum.track', { - track: link.track(track), - duration: strings.count.duration(track.duration) - })) - .map(row => `<li>${row}</li>`) - .join('\n'))} - </dd></ul> - `).join('\n')} - </dl> - `; - } - }, - - { - directory: 'tracks/by-times-referenced', - stringsKey: 'listTracks.byTimesReferenced', - - data({wikiData}) { - return wikiData.trackData - .map(track => ({track, timesReferenced: track.referencedBy.length})) - .filter(({ timesReferenced }) => timesReferenced > 0) - .sort((a, b) => b.timesReferenced - a.timesReferenced); - }, - - row({track, timesReferenced}, {link, strings}) { - return strings('listingPage.listTracks.byTimesReferenced.item', { - track: link.track(track), - timesReferenced: strings.count.timesReferenced(timesReferenced, {unit: true}) - }); - } - }, - - { - directory: 'tracks/in-flashes/by-album', - stringsKey: 'listTracks.inFlashes.byAlbum', - condition: ({wikiData}) => wikiData.wikiInfo.features.flashesAndGames, - - data({wikiData}) { - return chunkByProperties(wikiData.trackData - .filter(t => t.flashes.length > 0), ['album']) - .filter(({ album }) => album.directory !== UNRELEASED_TRACKS_DIRECTORY); - }, - - html(chunks, {link, strings}) { - return fixWS` - <dl> - ${chunks.map(({album, chunk: tracks}) => fixWS` - <dt>${strings('listingPage.listTracks.inFlashes.byAlbum.album', { - album: link.album(album), - date: strings.count.date(album.date) - })}</dt> - <dd><ul> - ${(tracks - .map(track => strings('listingPage.listTracks.inFlashes.byAlbum.track', { - track: link.track(track), - flashes: strings.list.and(track.flashes.map(link.flash)) - })) - .map(row => `<li>${row}</li>`) - .join('\n'))} - </dd></ul> - `).join('\n')} - </dl> - `; - } - }, - - { - directory: 'tracks/in-flashes/by-flash', - stringsKey: 'listTracks.inFlashes.byFlash', - condition: ({wikiData}) => wikiData.wikiInfo.features.flashesAndGames, - data: ({wikiData}) => wikiData.flashData, - - html(flashData, {link, strings}) { - return fixWS` - <dl> - ${sortByDate(flashData.slice()).map(flash => fixWS` - <dt>${strings('listingPage.listTracks.inFlashes.byFlash.flash', { - flash: link.flash(flash), - date: strings.count.date(flash.date) - })}</dt> - <dd><ul> - ${(flash.tracks - .map(track => strings('listingPage.listTracks.inFlashes.byFlash.track', { - track: link.track(track), - album: link.album(track.album) - })) - .map(row => `<li>${row}</li>`) - .join('\n'))} - </ul></dd> - `).join('\n')} - </dl> - `; - } - }, - - { - directory: 'tracks/with-lyrics', - stringsKey: 'listTracks.withLyrics', - - data({wikiData}) { - return chunkByProperties(wikiData.trackData.filter(t => t.lyrics), ['album']); - }, - - html(chunks, {link, strings}) { - return fixWS` - <dl> - ${chunks.map(({album, chunk: tracks}) => fixWS` - <dt>${strings('listingPage.listTracks.withLyrics.album', { - album: link.album(album), - date: strings.count.date(album.date) - })}</dt> - <dd><ul> - ${(tracks - .map(track => strings('listingPage.listTracks.withLyrics.track', { - track: link.track(track), - })) - .map(row => `<li>${row}</li>`) - .join('\n'))} - </dd></ul> - `).join('\n')} - </dl> - `; - } - }, - - { - directory: 'tags/by-name', - stringsKey: 'listTags.byName', - condition: ({wikiData}) => wikiData.wikiInfo.features.artTagUI, - - data({wikiData}) { - return wikiData.tagData - .filter(tag => !tag.isCW) - .sort(sortByName) - .map(tag => ({tag, timesUsed: tag.things.length})); - }, - - row({tag, timesUsed}, {link, strings}) { - return strings('listingPage.listTags.byName.item', { - tag: link.tag(tag), - timesUsed: strings.count.timesUsed(timesUsed, {unit: true}) - }); - } - }, - - { - directory: 'tags/by-uses', - stringsKey: 'listTags.byUses', - condition: ({wikiData}) => wikiData.wikiInfo.features.artTagUI, - - data({wikiData}) { - return wikiData.tagData - .filter(tag => !tag.isCW) - .map(tag => ({tag, timesUsed: tag.things.length})) - .sort((a, b) => b.timesUsed - a.timesUsed); - }, - - row({tag, timesUsed}, {link, strings}) { - return strings('listingPage.listTags.byUses.item', { - tag: link.tag(tag), - timesUsed: strings.count.timesUsed(timesUsed, {unit: true}) - }); - } - }, - - { - directory: 'random', - stringsKey: 'other.randomPages', - - data: ({wikiData}) => ({ - officialAlbumData: wikiData.officialAlbumData, - fandomAlbumData: wikiData.fandomAlbumData - }), - - html: ({officialAlbumData, fandomAlbumData}, { - getLinkThemeString, - strings - }) => fixWS` - <p>Choose a link to go to a random page in that category or album! If your browser doesn't support relatively modern JavaScript or you've disabled it, these links won't work - sorry.</p> - <p class="js-hide-once-data">(Data files are downloading in the background! Please wait for data to load.)</p> - <p class="js-show-once-data">(Data files have finished being downloaded. The links should work!)</p> - <dl> - <dt>Miscellaneous:</dt> - <dd><ul> - <li> - <a href="#" data-random="artist">Random Artist</a> - (<a href="#" data-random="artist-more-than-one-contrib">>1 contribution</a>) - </li> - <li><a href="#" data-random="album">Random Album (whole site)</a></li> - <li><a href="#" data-random="track">Random Track (whole site)</a></li> - </ul></dd> - ${[ - {name: 'Official', albumData: officialAlbumData, code: 'official'}, - {name: 'Fandom', albumData: fandomAlbumData, code: 'fandom'} - ].map(category => fixWS` - <dt>${category.name}: (<a href="#" data-random="album-in-${category.code}">Random Album</a>, <a href="#" data-random="track-in-${category.code}">Random Track</a>)</dt> - <dd><ul>${category.albumData.map(album => fixWS` - <li><a style="${getLinkThemeString(album.color)}; --album-directory: ${album.directory}" href="#" data-random="track-in-album">${album.name}</a></li> - `).join('\n')}</ul></dd> - `).join('\n')} - </dl> - ` + if (!empty(suberrors)) { + errors.push(new AggregateError(suberrors, `Errors matching "see also" listings for ${listing.directory}`)); + } + } else { + listing.seeAlso = null; } -]; + } -const filterListings = directoryPrefix => listingSpec - .filter(l => l.directory.startsWith(directoryPrefix)); + if (!empty(errors)) { + const aggregate = new AggregateError(errors, `Errors validating listings`); + showAggregate(aggregate, {showTraces: false}); + } +} + +const filterListings = (directoryPrefix) => + listingSpec.filter(l => l.directory.startsWith(directoryPrefix)); const listingTargetSpec = [ - { - title: ({strings}) => strings('listingPage.target.album'), - listings: filterListings('album') - }, - { - title: ({strings}) => strings('listingPage.target.artist'), - listings: filterListings('artist') - }, - { - title: ({strings}) => strings('listingPage.target.group'), - listings: filterListings('group') - }, - { - title: ({strings}) => strings('listingPage.target.track'), - listings: filterListings('track') - }, - { - title: ({strings}) => strings('listingPage.target.tag'), - listings: filterListings('tag') - }, - { - title: ({strings}) => strings('listingPage.target.other'), - listings: [ - listingSpec.find(l => l.directory === 'random') - ] - } + { + stringsKey: 'album', + listings: filterListings('album'), + }, + { + stringsKey: 'artist', + listings: filterListings('artist'), + }, + { + stringsKey: 'group', + listings: filterListings('group'), + }, + { + stringsKey: 'track', + listings: filterListings('track'), + }, + { + stringsKey: 'tag', + listings: filterListings('tag'), + }, + { + stringsKey: 'other', + listings: listingSpec.filter(l => l.groupUnderOther), + }, ]; +for (const target of listingTargetSpec) { + for (const listing of target.listings) { + listing.target = target; + } +} + export {listingSpec, listingTargetSpec}; |