« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/page
diff options
context:
space:
mode:
Diffstat (limited to 'src/page')
-rw-r--r--src/page/album-commentary.js243
-rw-r--r--src/page/album.js974
-rw-r--r--src/page/artist-alias.js25
-rw-r--r--src/page/artist.js1126
-rw-r--r--src/page/flash.js453
-rw-r--r--src/page/group.js471
-rw-r--r--src/page/homepage.js267
-rw-r--r--src/page/index.js2
-rw-r--r--src/page/listing.js321
-rw-r--r--src/page/news.js193
-rw-r--r--src/page/static.js39
-rw-r--r--src/page/tag.js144
-rw-r--r--src/page/track.js643
13 files changed, 2813 insertions, 2088 deletions
diff --git a/src/page/album-commentary.js b/src/page/album-commentary.js
index 57135a4a..43b8c8d6 100644
--- a/src/page/album-commentary.js
+++ b/src/page/album-commentary.js
@@ -1,144 +1,133 @@
+/** @format */
+
 // Album commentary page and index specifications.
 
 // Imports
 
-import fixWS from 'fix-whitespace';
-
-import {
-    filterAlbumsByCommentary
-} from '../util/wiki-data.js';
+import * as html from '../util/html.js';
+import {filterAlbumsByCommentary} from '../util/wiki-data.js';
 
 // Page exports
 
 export function condition({wikiData}) {
-    return filterAlbumsByCommentary(wikiData.albumData).length;
+  return filterAlbumsByCommentary(wikiData.albumData).length;
 }
 
 export function targets({wikiData}) {
-    return filterAlbumsByCommentary(wikiData.albumData);
+  return filterAlbumsByCommentary(wikiData.albumData);
 }
 
-export function write(album, {wikiData}) {
-    const { wikiInfo } = wikiData;
-
-    const entries = [album, ...album.tracks].filter(x => x.commentary).map(x => x.commentary);
-    const words = entries.join(' ').split(' ').length;
-
-    const page = {
-        type: 'page',
-        path: ['albumCommentary', album.directory],
-        page: ({
-            getAlbumStylesheet,
-            getLinkThemeString,
-            getThemeString,
-            link,
-            language,
-            to,
-            transformMultiline
-        }) => ({
-            title: language.$('albumCommentaryPage.title', {album: album.name}),
-            stylesheet: getAlbumStylesheet(album),
-            theme: getThemeString(album.color),
-
-            main: {
-                content: fixWS`
-                    <div class="long-content">
-                        <h1>${language.$('albumCommentaryPage.title', {
-                            album: link.album(album)
-                        })}</h1>
-                        <p>${language.$('albumCommentaryPage.infoLine', {
-                            words: `<b>${language.formatWordCount(words, {unit: true})}</b>`,
-                            entries: `<b>${language.countCommentaryEntries(entries.length, {unit: true})}</b>`
-                        })}</p>
-                        ${album.commentary && fixWS`
-                            <h3>${language.$('albumCommentaryPage.entry.title.albumCommentary')}</h3>
-                            <blockquote>
-                                ${transformMultiline(album.commentary)}
-                            </blockquote>
-                        `}
-                        ${album.tracks.filter(t => t.commentary).map(track => fixWS`
-                            <h3 id="${track.directory}">${language.$('albumCommentaryPage.entry.title.trackCommentary', {
-                                track: link.track(track)
-                            })}</h3>
-                            <blockquote style="${getLinkThemeString(track.color)}">
-                                ${transformMultiline(track.commentary)}
-                            </blockquote>
-                        `).join('\n')}
-                    </div>
-                `
-            },
-
-            nav: {
-                linkContainerClasses: ['nav-links-hierarchy'],
-                links: [
-                    {toHome: true},
-                    {
-                        path: ['localized.commentaryIndex'],
-                        title: language.$('commentaryIndex.title')
-                    },
-                    {
-                        html: language.$('albumCommentaryPage.nav.album', {
-                            album: link.albumCommentary(album, {class: 'current'})
-                        })
-                    }
-                ]
-            }
-        })
-    };
-
-    return [page];
+export function write(album) {
+  const entries = [album, ...album.tracks]
+    .filter((x) => x.commentary)
+    .map((x) => x.commentary);
+  const words = entries.join(' ').split(' ').length;
+
+  const page = {
+    type: 'page',
+    path: ['albumCommentary', album.directory],
+    page: ({
+      getAlbumStylesheet,
+      getLinkThemeString,
+      getThemeString,
+      link,
+      language,
+      transformMultiline,
+    }) => ({
+      title: language.$('albumCommentaryPage.title', {album: album.name}),
+      stylesheet: getAlbumStylesheet(album),
+      theme: getThemeString(album.color),
+
+      main: {
+        content: html.tag('div', {class: 'long-content'}, [
+          html.tag('h1', language.$('albumCommentaryPage.title', {
+            album: link.album(album),
+          })),
+          html.tag('p', language.$('albumCommentaryPage.infoLine', {
+            words: html.tag('b', language.formatWordCount(words, {unit: true})),
+            entries: html.tag('b', language.countCommentaryEntries(entries.length, {unit: true})),
+          })),
+          ...album.commentary ? [
+            html.tag('h3', language.$('albumCommentaryPage.entry.title.albumCommentary')),
+            html.tag('blockquote', transformMultiline(album.commentary)),
+          ] : [],
+          ...album.tracks.filter(t => t.commentary).flatMap(track => [
+            html.tag('h3',
+              {id: 'track.directory'},
+              language.$('albumCommentaryPage.entry.title.trackCommentary', {
+                track: link.track(track),
+              })),
+            html.tag('blockquote',
+              {style: getLinkThemeString(track.color)},
+              transformMultiline(track.commentary)),
+          ])
+        ]),
+      },
+
+      nav: {
+        linkContainerClasses: ['nav-links-hierarchy'],
+        links: [
+          {toHome: true},
+          {
+            path: ['localized.commentaryIndex'],
+            title: language.$('commentaryIndex.title'),
+          },
+          {
+            html: language.$('albumCommentaryPage.nav.album', {
+              album: link.albumCommentary(album, {class: 'current'}),
+            }),
+          },
+        ],
+      },
+    }),
+  };
+
+  return [page];
 }
 
 export function writeTargetless({wikiData}) {
-    const data = filterAlbumsByCommentary(wikiData.albumData)
-        .map(album => ({
-            album,
-            entries: [album, ...album.tracks].filter(x => x.commentary).map(x => x.commentary)
-        }))
-        .map(({ album, entries }) => ({
-            album, entries,
-            words: entries.join(' ').split(' ').length
-        }));
-
-    const totalEntries = data.reduce((acc, {entries}) => acc + entries.length, 0);
-    const totalWords = data.reduce((acc, {words}) => acc + words, 0);
-
-    const page = {
-        type: 'page',
-        path: ['commentaryIndex'],
-        page: ({
-            link,
-            language
-        }) => ({
-            title: language.$('commentaryIndex.title'),
-
-            main: {
-                content: fixWS`
-                    <div class="long-content">
-                        <h1>${language.$('commentaryIndex.title')}</h1>
-                        <p>${language.$('commentaryIndex.infoLine', {
-                            words: `<b>${language.formatWordCount(totalWords, {unit: true})}</b>`,
-                            entries: `<b>${language.countCommentaryEntries(totalEntries, {unit: true})}</b>`
-                        })}</p>
-                        <p>${language.$('commentaryIndex.albumList.title')}</p>
-                        <ul>
-                            ${data
-                                .map(({ album, entries, words }) => fixWS`
-                                    <li>${language.$('commentaryIndex.albumList.item', {
-                                        album: link.albumCommentary(album),
-                                        words: language.formatWordCount(words, {unit: true}),
-                                        entries: language.countCommentaryEntries(entries.length, {unit: true})
-                                    })}</li>
-                                `)
-                                .join('\n')}
-                        </ul>
-                    </div>
-                `
-            },
-
-            nav: {simple: true}
-        })
-    };
-
-    return [page];
+  const data = filterAlbumsByCommentary(wikiData.albumData)
+    .map((album) => ({
+      album,
+      entries: [album, ...album.tracks]
+        .filter((x) => x.commentary)
+        .map((x) => x.commentary),
+    }))
+    .map(({album, entries}) => ({
+      album,
+      entries,
+      words: entries.join(' ').split(' ').length,
+    }));
+
+  const totalEntries = data.reduce((acc, {entries}) => acc + entries.length, 0);
+  const totalWords = data.reduce((acc, {words}) => acc + words, 0);
+
+  const page = {
+    type: 'page',
+    path: ['commentaryIndex'],
+    page: ({link, language}) => ({
+      title: language.$('commentaryIndex.title'),
+
+      main: {
+        content: html.tag('div', {class: 'long-content'}, [
+          html.tag('h1', language.$('commentaryIndex.title')),
+          html.tag('p', language.$('commentaryIndex.infoLine', {
+            words: html.tag('b', language.formatWordCount(totalWords, {unit: true})),
+            entries: html.tag('b', language.countCommentaryEntries(totalEntries, {unit: true})),
+          })),
+          html.tag('p', language.$('commentaryIndex.albumList.title')),
+          html.tag('ul', data.map(({album, entries, words}) =>
+            html.tag('li', language.$('commentaryIndex.albumList.item', {
+              album: link.albumCommentary(album),
+              words: language.formatWordCount(words, {unit: true}),
+              entries: language.countCommentaryEntries(entries.length, {unit: true}),
+            }))))
+        ]),
+      },
+
+      nav: {simple: true},
+    }),
+  };
+
+  return [page];
 }
diff --git a/src/page/album.js b/src/page/album.js
index c265fdc6..12755ae9 100644
--- a/src/page/album.js
+++ b/src/page/album.js
@@ -1,3 +1,5 @@
+/** @format */
+
 // Album page specification.
 
 // Imports
@@ -6,480 +8,644 @@ import fixWS from 'fix-whitespace';
 
 import * as html from '../util/html.js';
 
-import {
-    bindOpts,
-    compareArrays,
-} from '../util/sugar.js';
+import {bindOpts, compareArrays} from '../util/sugar.js';
 
 import {
-    getAlbumCover,
-    getAlbumListTag,
-    getTotalDuration,
+  getAlbumCover,
+  getAlbumListTag,
+  getTotalDuration,
 } from '../util/wiki-data.js';
 
 // Page exports
 
 export function targets({wikiData}) {
-    return wikiData.albumData;
+  return wikiData.albumData;
 }
 
 export function write(album, {wikiData}) {
-    const { wikiInfo } = wikiData;
-
-    const unbound_trackToListItem = (track, {
+  const unbound_trackToListItem = (
+    track,
+    {getArtistString, getLinkThemeString, link, language}
+  ) => {
+    const itemOpts = {
+      duration: language.formatDuration(track.duration ?? 0),
+      track: link.track(track),
+    };
+    return `<li style="${getLinkThemeString(track.color)}">${
+      compareArrays(
+        track.artistContribs.map((c) => c.who),
+        album.artistContribs.map((c) => c.who),
+        {checkOrder: false}
+      )
+        ? language.$('trackList.item.withDuration', itemOpts)
+        : language.$('trackList.item.withDuration.withArtists', {
+            ...itemOpts,
+            by: `<span class="by">${language.$(
+              'trackList.item.withArtists.by',
+              {
+                artists: getArtistString(track.artistContribs),
+              }
+            )}</span>`,
+          })
+    }</li>`;
+  };
+
+  const hasCommentaryEntries =
+    [album, ...album.tracks].filter((x) => x.commentary).length > 0;
+  const hasAdditionalFiles = album.additionalFiles?.length > 0;
+  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.dateAddedToWiki,
+      },
+      duration: albumDuration,
+      color: album.color,
+      cover: serializeCover(album, getAlbumCover),
+      artistContribs: serializeContribs(album.artistContribs),
+      coverArtistContribs: serializeContribs(album.coverArtistContribs),
+      wallpaperArtistContribs: serializeContribs(album.wallpaperArtistContribs),
+      bannerArtistContribs: serializeContribs(album.bannerArtistContribs),
+      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: ({
+      fancifyURL,
+      generateAdditionalFilesShortcut,
+      generateAdditionalFilesList,
+      generateChronologyLinks,
+      generateCoverLink,
+      getAlbumCover,
+      getAlbumStylesheet,
+      getArtistString,
+      getLinkThemeString,
+      getSizeOfAdditionalFile,
+      getThemeString,
+      link,
+      language,
+      transformMultiline,
+      urls,
+    }) => {
+      const trackToListItem = bindOpts(unbound_trackToListItem, {
         getArtistString,
         getLinkThemeString,
         link,
-        language
-    }) => {
-        const itemOpts = {
-            duration: language.formatDuration(track.duration ?? 0),
-            track: link.track(track)
-        };
-        return `<li style="${getLinkThemeString(track.color)}">${
-            (compareArrays(
-                track.artistContribs.map(c => c.who),
-                album.artistContribs.map(c => c.who),
-                {checkOrder: false})
-                ? language.$('trackList.item.withDuration', itemOpts)
-                : language.$('trackList.item.withDuration.withArtists', {
-                    ...itemOpts,
-                    by: `<span class="by">${
-                        language.$('trackList.item.withArtists.by', {
-                            artists: getArtistString(track.artistContribs)
-                        })
-                    }</span>`
-                }))
-        }</li>`;
-    };
-
-    const hasCommentaryEntries = ([album, ...album.tracks].filter(x => x.commentary).length > 0);
-    const hasAdditionalFiles = (album.additionalFiles?.length > 0);
-    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.dateAddedToWiki
-            },
-            duration: albumDuration,
-            color: album.color,
-            cover: serializeCover(album, getAlbumCover),
-            artistContribs: serializeContribs(album.artistContribs),
-            coverArtistContribs: serializeContribs(album.coverArtistContribs),
-            wallpaperArtistContribs: serializeContribs(album.wallpaperArtistContribs),
-            bannerArtistContribs: serializeContribs(album.bannerArtistContribs),
-            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: ({
-            fancifyURL,
-            generateAdditionalFilesShortcut,
-            generateAdditionalFilesList,
-            generateChronologyLinks,
-            generateCoverLink,
-            getAlbumCover,
-            getAlbumStylesheet,
-            getArtistString,
-            getLinkThemeString,
-            getSizeOfAdditionalFile,
-            getThemeString,
-            link,
-            language,
-            transformMultiline,
-            urls,
-        }) => {
-            const trackToListItem = bindOpts(unbound_trackToListItem, {
-                getArtistString,
-                getLinkThemeString,
-                link,
-                language
-            });
-
-            const cover = getAlbumCover(album);
-
-            return {
-                title: language.$('albumPage.title', {album: album.name}),
-                stylesheet: getAlbumStylesheet(album),
-                theme: getThemeString(album.color, [
-                    `--album-directory: ${album.directory}`
-                ]),
-
-                banner: album.bannerArtistContribs.length && {
-                    dimensions: album.bannerDimensions,
-                    path: ['media.albumBanner', album.directory, album.bannerFileExtension],
-                    alt: language.$('misc.alt.albumBanner'),
-                    position: 'top'
-                },
-
-                main: {
-                    content: fixWS`
-                        ${cover && generateCoverLink({
+        language,
+      });
+
+      const cover = getAlbumCover(album);
+
+      return {
+        title: language.$('albumPage.title', {album: album.name}),
+        stylesheet: getAlbumStylesheet(album),
+        theme: getThemeString(album.color, [
+          `--album-directory: ${album.directory}`,
+        ]),
+
+        banner: album.bannerArtistContribs.length && {
+          dimensions: album.bannerDimensions,
+          path: [
+            'media.albumBanner',
+            album.directory,
+            album.bannerFileExtension,
+          ],
+          alt: language.$('misc.alt.albumBanner'),
+          position: 'top',
+        },
+
+        main: {
+          content: fixWS`
+                        ${
+                          cover &&
+                          generateCoverLink({
                             src: cover,
                             alt: language.$('misc.alt.albumCover'),
-                            tags: album.artTags
-                        })}
-                        <h1>${language.$('albumPage.title', {album: album.name})}</h1>
+                            tags: album.artTags,
+                          })
+                        }
+                        <h1>${language.$('albumPage.title', {
+                          album: album.name,
+                        })}</h1>
                         <p>
                             ${[
-                                album.artistContribs.length && language.$('releaseInfo.by', {
-                                    artists: getArtistString(album.artistContribs, {
-                                        showContrib: true,
-                                        showIcons: true
-                                    })
+                              album.artistContribs.length &&
+                                language.$('releaseInfo.by', {
+                                  artists: getArtistString(
+                                    album.artistContribs,
+                                    {
+                                      showContrib: true,
+                                      showIcons: true,
+                                    }
+                                  ),
+                                }),
+                              album.coverArtistContribs.length &&
+                                language.$('releaseInfo.coverArtBy', {
+                                  artists: getArtistString(
+                                    album.coverArtistContribs,
+                                    {
+                                      showContrib: true,
+                                      showIcons: true,
+                                    }
+                                  ),
                                 }),
-                                album.coverArtistContribs.length && language.$('releaseInfo.coverArtBy', {
-                                    artists: getArtistString(album.coverArtistContribs, {
-                                        showContrib: true,
-                                        showIcons: true
-                                    })
+                              album.wallpaperArtistContribs.length &&
+                                language.$('releaseInfo.wallpaperArtBy', {
+                                  artists: getArtistString(
+                                    album.wallpaperArtistContribs,
+                                    {
+                                      showContrib: true,
+                                      showIcons: true,
+                                    }
+                                  ),
                                 }),
-                                album.wallpaperArtistContribs.length && language.$('releaseInfo.wallpaperArtBy', {
-                                    artists: getArtistString(album.wallpaperArtistContribs, {
-                                        showContrib: true,
-                                        showIcons: true
-                                    })
+                              album.bannerArtistContribs.length &&
+                                language.$('releaseInfo.bannerArtBy', {
+                                  artists: getArtistString(
+                                    album.bannerArtistContribs,
+                                    {
+                                      showContrib: true,
+                                      showIcons: true,
+                                    }
+                                  ),
                                 }),
-                                album.bannerArtistContribs.length && language.$('releaseInfo.bannerArtBy', {
-                                    artists: getArtistString(album.bannerArtistContribs, {
-                                        showContrib: true,
-                                        showIcons: true
-                                    })
+                              album.date &&
+                                language.$('releaseInfo.released', {
+                                  date: language.formatDate(album.date),
                                 }),
-                                album.date && language.$('releaseInfo.released', {
-                                    date: language.formatDate(album.date)
+                              album.coverArtDate &&
+                                +album.coverArtDate !== +album.date &&
+                                language.$('releaseInfo.artReleased', {
+                                  date: language.formatDate(album.coverArtDate),
                                 }),
-                                (album.coverArtDate &&
-                                    +album.coverArtDate !== +album.date &&
-                                    language.$('releaseInfo.artReleased', {
-                                        date: language.formatDate(album.coverArtDate)
-                                    })),
-                                language.$('releaseInfo.duration', {
-                                    duration: language.formatDuration(albumDuration, {approximate: album.tracks.length > 1})
-                                })
-                            ].filter(Boolean).join('<br>\n')}
+                              language.$('releaseInfo.duration', {
+                                duration: language.formatDuration(
+                                  albumDuration,
+                                  {
+                                    approximate: album.tracks.length > 1,
+                                  }
+                                ),
+                              }),
+                            ]
+                              .filter(Boolean)
+                              .join('<br>\n')}
                         </p>
-                        ${(hasAdditionalFiles || hasCommentaryEntries) && fixWS`<p>
+                        ${
+                          (hasAdditionalFiles || hasCommentaryEntries) &&
+                          fixWS`<p>
                             ${[
-                                hasAdditionalFiles && generateAdditionalFilesShortcut(album.additionalFiles, {language}),
-                                hasCommentaryEntries && language.$('releaseInfo.viewCommentary', {
-                                    link: link.albumCommentary(album, {
-                                        text: language.$('releaseInfo.viewCommentary.link')
-                                    })
-                                })
-                            ].filter(Boolean).join('<br>\n')
-                        }</p>`}
-                        ${album.urls?.length && `<p>${
-                            language.$('releaseInfo.listenOn', {
-                                links: language.formatDisjunctionList(album.urls.map(url => fancifyURL(url, {album: true})))
-                            })
-                        }</p>`}
-                        ${album.trackGroups && (album.trackGroups.length > 1 || !album.trackGroups[0].isDefaultTrackGroup) ? fixWS`
+                              hasAdditionalFiles &&
+                                generateAdditionalFilesShortcut(
+                                  album.additionalFiles,
+                                  {
+                                    language,
+                                  }
+                                ),
+                              hasCommentaryEntries &&
+                                language.$('releaseInfo.viewCommentary', {
+                                  link: link.albumCommentary(album, {
+                                    text: language.$(
+                                      'releaseInfo.viewCommentary.link'
+                                    ),
+                                  }),
+                                }),
+                            ]
+                              .filter(Boolean)
+                              .join('<br>\n')}</p>`
+                        }
+                        ${
+                          album.urls?.length &&
+                          `<p>${language.$('releaseInfo.listenOn', {
+                            links: language.formatDisjunctionList(
+                              album.urls.map((url) =>
+                                fancifyURL(url, {album: true})
+                              )
+                            ),
+                          })}</p>`
+                        }
+                        ${
+                          album.trackGroups &&
+                          (album.trackGroups.length > 1 ||
+                            !album.trackGroups[0].isDefaultTrackGroup)
+                            ? fixWS`
                             <dl class="album-group-list">
-                                ${album.trackGroups.map(({ name, color, startIndex, tracks }) => fixWS`
-                                    <dt>${
-                                        language.$('trackList.section.withDuration', {
-                                            duration: language.formatDuration(getTotalDuration(tracks), {approximate: tracks.length > 1}),
-                                            section: name
-                                        })
-                                    }</dt>
-                                    <dd><${listTag === 'ol' ? `ol start="${startIndex + 1}"` : listTag}>
-                                        ${tracks.map(trackToListItem).join('\n')}
+                                ${album.trackGroups
+                                  .map(
+                                    ({
+                                      name,
+                                      startIndex,
+                                      tracks,
+                                    }) => fixWS`
+                                    <dt>${language.$(
+                                      'trackList.section.withDuration',
+                                      {
+                                        duration: language.formatDuration(
+                                          getTotalDuration(tracks),
+                                          {
+                                            approximate: tracks.length > 1,
+                                          }
+                                        ),
+                                        section: name,
+                                      }
+                                    )}</dt>
+                                    <dd><${
+                                      listTag === 'ol'
+                                        ? `ol start="${startIndex + 1}"`
+                                        : listTag
+                                    }>
+                                        ${tracks
+                                          .map(trackToListItem)
+                                          .join('\n')}
                                     </${listTag}></dd>
-                                `).join('\n')}
+                                `
+                                  )
+                                  .join('\n')}
                             </dl>
-                        ` : fixWS`
+                        `
+                            : fixWS`
                             <${listTag}>
                                 ${album.tracks.map(trackToListItem).join('\n')}
                             </${listTag}>
-                        `}
-                        ${album.dateAddedToWiki && fixWS`
+                        `
+                        }
+                        ${
+                          album.dateAddedToWiki &&
+                          fixWS`
                             <p>
                                 ${[
-                                    language.$('releaseInfo.addedToWiki', {
-                                        date: language.formatDate(album.dateAddedToWiki)
-                                    })
-                                ].filter(Boolean).join('<br>\n')}
+                                  language.$('releaseInfo.addedToWiki', {
+                                    date: language.formatDate(
+                                      album.dateAddedToWiki
+                                    ),
+                                  }),
+                                ]
+                                  .filter(Boolean)
+                                  .join('<br>\n')}
                             </p>
-                        `}
-                        ${hasAdditionalFiles && generateAdditionalFilesList(album.additionalFiles, {
+                        `
+                        }
+                        ${
+                          hasAdditionalFiles &&
+                          generateAdditionalFilesList(album.additionalFiles, {
                             // TODO: Kinda near the metal here...
-                            getFileSize: file => getSizeOfAdditionalFile(urls
-                                .from('media.root')
-                                .to('media.albumAdditionalFile', album.directory, file)),
-                            linkFile: file => link.albumAdditionalFile({album, file}),
-                        })}
-                        ${album.commentary && fixWS`
+                            getFileSize: (file) =>
+                              getSizeOfAdditionalFile(
+                                urls
+                                  .from('media.root')
+                                  .to(
+                                    'media.albumAdditionalFile',
+                                    album.directory,
+                                    file
+                                  )
+                              ),
+                            linkFile: (file) =>
+                              link.albumAdditionalFile({album, file}),
+                          })
+                        }
+                        ${
+                          album.commentary &&
+                          fixWS`
                             <p>${language.$('releaseInfo.artistCommentary')}</p>
                             <blockquote>
                                 ${transformMultiline(album.commentary)}
                             </blockquote>
-                        `}
-                    `
-                },
-
-                sidebarLeft: generateAlbumSidebar(album, null, {
-                    fancifyURL,
-                    getLinkThemeString,
-                    link,
-                    language,
-                    transformMultiline,
-                    wikiData
-                }),
-
-                nav: {
-                    linkContainerClasses: ['nav-links-hierarchy'],
-                    links: [
-                        {toHome: true},
-                        {
-                            html: language.$('albumPage.nav.album', {
-                                album: link.album(album, {class: 'current'})
-                            })
-                        },
-                    ],
-                    bottomRowContent: generateAlbumNavLinks(album, null, {language}),
-                    content: generateAlbumChronologyLinks(album, null, {generateChronologyLinks}),
-                },
-
-                secondaryNav: generateAlbumSecondaryNav(album, null, {
-                    language,
-                    link,
-                    getLinkThemeString,
-                }),
-            };
-        }
-    };
+                        `
+                        }
+                    `,
+        },
+
+        sidebarLeft: generateAlbumSidebar(album, null, {
+          fancifyURL,
+          getLinkThemeString,
+          link,
+          language,
+          transformMultiline,
+          wikiData,
+        }),
+
+        nav: {
+          linkContainerClasses: ['nav-links-hierarchy'],
+          links: [
+            {toHome: true},
+            {
+              html: language.$('albumPage.nav.album', {
+                album: link.album(album, {class: 'current'}),
+              }),
+            },
+          ],
+          bottomRowContent: generateAlbumNavLinks(album, null, {language}),
+          content: generateAlbumChronologyLinks(album, null, {
+            generateChronologyLinks,
+          }),
+        },
+
+        secondaryNav: generateAlbumSecondaryNav(album, null, {
+          language,
+          link,
+          getLinkThemeString,
+        }),
+      };
+    },
+  };
 
-    return [page, data];
+  return [page, data];
 }
 
 // Utility functions
 
 export function generateAlbumSidebar(album, currentTrack, {
-    fancifyURL,
-    getLinkThemeString,
-    link,
-    language,
-    transformMultiline,
-    wikiData
+  fancifyURL,
+  getLinkThemeString,
+  link,
+  language,
+  transformMultiline,
 }) {
-    const listTag = getAlbumListTag(album);
-
-    /*
-    const trackGroups = album.trackGroups || [{
-        name: language.$('albumSidebar.trackList.fallbackGroupName'),
-        color: album.color,
-        startIndex: 0,
-        tracks: album.tracks
-    }];
-    */
-
-    const { trackGroups } = album;
-
-    const trackToListItem = track => html.tag('li',
-        {class: track === currentTrack && 'current'},
-        language.$('albumSidebar.trackList.item', {
-            track: link.track(track)
-        }));
-
-    const nameOrDefault = (isDefaultTrackGroup, name) =>
-        (isDefaultTrackGroup
-            ? language.$('albumSidebar.trackList.fallbackGroupName')
-            : name);
-
-    const trackListPart = fixWS`
+  const listTag = getAlbumListTag(album);
+
+  /*
+  const trackGroups = album.trackGroups || [{
+      name: language.$('albumSidebar.trackList.fallbackGroupName'),
+      color: album.color,
+      startIndex: 0,
+      tracks: album.tracks
+  }];
+  */
+
+  const {trackGroups} = album;
+
+  const trackToListItem = (track) =>
+    html.tag(
+      'li',
+      {class: track === currentTrack && 'current'},
+      language.$('albumSidebar.trackList.item', {
+        track: link.track(track),
+      })
+    );
+
+  const nameOrDefault = (isDefaultTrackGroup, name) =>
+    isDefaultTrackGroup
+      ? language.$('albumSidebar.trackList.fallbackGroupName')
+      : name;
+
+  const trackListPart = fixWS`
         <h1>${link.album(album)}</h1>
-        ${trackGroups.map(({ name, color, startIndex, tracks, isDefaultTrackGroup }) =>
-            html.tag('details', {
+        ${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
                 // in the main content area.
                 open: currentTrack && tracks.includes(currentTrack),
-                class: tracks.includes(currentTrack) && 'current'
-            }, [
-                html.tag('summary',
-                    {style: getLinkThemeString(color)},
-                    (listTag === 'ol'
-                        ? language.$('albumSidebar.trackList.group.withRange', {
-                            group: `<span class="group-name">${nameOrDefault(isDefaultTrackGroup, name)}</span>`,
-                            range: `${startIndex + 1}&ndash;${startIndex + tracks.length}`
-                        })
-                        : language.$('albumSidebar.trackList.group', {
-                            group: `<span class="group-name">${nameOrDefault(isDefaultTrackGroup, name)}</span>`
-                        }))
+                class: tracks.includes(currentTrack) && 'current',
+              },
+              [
+                html.tag(
+                  'summary',
+                  {style: getLinkThemeString(color)},
+                  listTag === 'ol'
+                    ? language.$('albumSidebar.trackList.group.withRange', {
+                        group: `<span class="group-name">${nameOrDefault(
+                          isDefaultTrackGroup,
+                          name
+                        )}</span>`,
+                        range: `${startIndex + 1}&ndash;${
+                          startIndex + tracks.length
+                        }`,
+                      })
+                    : language.$('albumSidebar.trackList.group', {
+                        group: `<span class="group-name">${nameOrDefault(
+                          isDefaultTrackGroup,
+                          name
+                        )}</span>`,
+                      })
                 ),
                 fixWS`
-                    <${listTag === 'ol' ? `ol start="${startIndex + 1}"` : listTag}>
+                    <${
+                      listTag === 'ol'
+                        ? `ol start="${startIndex + 1}"`
+                        : listTag
+                    }>
                         ${tracks.map(trackToListItem).join('\n')}
                     </${listTag}>
-                `
-            ])).join('\n')}
+                `,
+              ]
+            )
+          )
+          .join('\n')}
     `;
 
-    const { groups } = album;
-
-    const groupParts = groups.map(group => {
-        const albums = group.albums.filter(album => album.date);
-        const index = albums.indexOf(album);
-        const next = index >= 0 && albums[index + 1];
-        const previous = index > 0 && albums[index - 1];
-        return {group, next, previous};
-    }).map(({group, next, previous}) => fixWS`
-        <h1>${
-            language.$('albumSidebar.groupBox.title', {
-                group: link.groupInfo(group)
-            })
-        }</h1>
+  const {groups} = album;
+
+  const groupParts = groups
+    .map((group) => {
+      const albums = group.albums.filter((album) => album.date);
+      const index = albums.indexOf(album);
+      const next = index >= 0 && albums[index + 1];
+      const previous = index > 0 && albums[index - 1];
+      return {group, next, previous};
+    })
+    .map(
+      ({group, next, previous}) => fixWS`
+        <h1>${language.$('albumSidebar.groupBox.title', {
+          group: link.groupInfo(group),
+        })}</h1>
         ${!currentTrack && transformMultiline(group.descriptionShort)}
-        ${group.urls?.length && `<p>${
-            language.$('releaseInfo.visitOn', {
-                links: language.formatDisjunctionList(group.urls.map(url => fancifyURL(url)))
-            })
-        }</p>`}
-        ${!currentTrack && fixWS`
-            ${next && `<p class="group-chronology-link">${
-                language.$('albumSidebar.groupBox.next', {
-                    album: link.album(next)
-                })
-            }</p>`}
-            ${previous && `<p class="group-chronology-link">${
-                language.$('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
-                ]
-            };
+        ${
+          group.urls?.length &&
+          `<p>${language.$('releaseInfo.visitOn', {
+            links: language.formatDisjunctionList(
+              group.urls.map((url) => fancifyURL(url))
+            ),
+          })}</p>`
         }
+        ${
+          !currentTrack &&
+          fixWS`
+            ${
+              next &&
+              `<p class="group-chronology-link">${language.$(
+                'albumSidebar.groupBox.next',
+                {
+                  album: link.album(next),
+                }
+              )}</p>`
+            }
+            ${
+              previous &&
+              `<p class="group-chronology-link">${language.$(
+                '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 {
-            content: trackListPart
-        };
+      return {
+        multiple: [...groupParts, trackListPart],
+      };
     }
+  } else {
+    return {
+      content: trackListPart,
+    };
+  }
 }
 
-export function generateAlbumSecondaryNav(album, currentTrack, {
-    link,
-    language,
-    getLinkThemeString,
-}) {
-    const { groups } = album;
-
-    if (!groups.length) {
-        return null;
-    }
-
-    const groupParts = groups.map(group => {
-        const albums = group.albums.filter(album => album.date);
-        const index = albums.indexOf(album);
-        const next = index >= 0 && albums[index + 1];
-        const previous = index > 0 && albums[index - 1];
-        return {group, next, previous};
-    }).map(({group, next, previous}) => {
-        const previousNext = !currentTrack && [
-            previous && link.album(previous, {color: false, text: language.$('misc.nav.previous')}),
-            next && link.album(next, {color: false, text: language.$('misc.nav.next')})
-        ].filter(Boolean);
-        return html.tag('span', {style: getLinkThemeString(group.color)}, [
-            language.$('albumSidebar.groupBox.title', {
-                group: link.groupInfo(group)
+export function generateAlbumSecondaryNav(
+  album,
+  currentTrack,
+  {link, language, getLinkThemeString}
+) {
+  const {groups} = album;
+
+  if (!groups.length) {
+    return null;
+  }
+
+  const groupParts = groups
+    .map((group) => {
+      const albums = group.albums.filter((album) => album.date);
+      const index = albums.indexOf(album);
+      const next = index >= 0 && albums[index + 1];
+      const previous = index > 0 && albums[index - 1];
+      return {group, next, previous};
+    })
+    .map(({group, next, previous}) => {
+      const previousNext =
+        !currentTrack &&
+        [
+          previous &&
+            link.album(previous, {
+              color: false,
+              text: language.$('misc.nav.previous'),
+            }),
+          next &&
+            link.album(next, {
+              color: false,
+              text: language.$('misc.nav.next'),
             }),
-            previousNext?.length && `(${previousNext.join(',\n')})`
-        ]);
+        ].filter(Boolean);
+      return html.tag('span', {style: getLinkThemeString(group.color)}, [
+        language.$('albumSidebar.groupBox.title', {
+          group: link.groupInfo(group),
+        }),
+        previousNext?.length && `(${previousNext.join(',\n')})`,
+      ]);
     });
 
-    return {
-        classes: ['dot-between-spans'],
-        content: groupParts.join('\n'),
-    };
+  return {
+    classes: ['dot-between-spans'],
+    content: groupParts.join('\n'),
+  };
 }
 
-export function generateAlbumNavLinks(album, currentTrack, {
-    generatePreviousNextLinks,
-    language
-}) {
-    if (album.tracks.length <= 1) {
-        return '';
-    }
-
-    const previousNextLinks = currentTrack && generatePreviousNextLinks(currentTrack, {
-        data: album.tracks,
-        linkKey: 'track'
+export function generateAlbumNavLinks(
+  album,
+  currentTrack,
+  {generatePreviousNextLinks, language}
+) {
+  if (album.tracks.length <= 1) {
+    return '';
+  }
+
+  const previousNextLinks =
+    currentTrack &&
+    generatePreviousNextLinks(currentTrack, {
+      data: album.tracks,
+      linkKey: 'track',
     });
-    const randomLink = `<a href="#" data-random="track-in-album" id="random-button">${
-        (currentTrack
-            ? language.$('trackPage.nav.random')
-            : language.$('albumPage.nav.randomTrack'))
-    }</a>`;
-
-    return (previousNextLinks
-        ? `(${previousNextLinks}<span class="js-hide-until-data">, ${randomLink}</span>)`
-        : `<span class="js-hide-until-data">(${randomLink})</span>`);
+  const randomLink = `<a href="#" data-random="track-in-album" id="random-button">${
+    currentTrack
+      ? language.$('trackPage.nav.random')
+      : language.$('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, {generateChronologyLinks}) {
-    return html.tag('div', {
-        [html.onlyIfContent]: true,
-        class: 'nav-chronology-links',
-    }, [
-        currentTrack && generateChronologyLinks(currentTrack, {
-            contribKey: 'artistContribs',
-            getThings: artist => [...artist.tracksAsArtist, ...artist.tracksAsContributor],
-            headingString: 'misc.chronology.heading.track'
+export function generateAlbumChronologyLinks(
+  album,
+  currentTrack,
+  {generateChronologyLinks}
+) {
+  return html.tag(
+    'div',
+    {
+      [html.onlyIfContent]: true,
+      class: 'nav-chronology-links',
+    },
+    [
+      currentTrack &&
+        generateChronologyLinks(currentTrack, {
+          contribKey: 'artistContribs',
+          getThings: (artist) => [
+            ...artist.tracksAsArtist,
+            ...artist.tracksAsContributor,
+          ],
+          headingString: 'misc.chronology.heading.track',
         }),
-        currentTrack && generateChronologyLinks(currentTrack, {
-            contribKey: 'contributorContribs',
-            getThings: artist => [...artist.tracksAsArtist, ...artist.tracksAsContributor],
-            headingString: 'misc.chronology.heading.track'
+      currentTrack &&
+        generateChronologyLinks(currentTrack, {
+          contribKey: 'contributorContribs',
+          getThings: (artist) => [
+            ...artist.tracksAsArtist,
+            ...artist.tracksAsContributor,
+          ],
+          headingString: 'misc.chronology.heading.track',
         }),
-        generateChronologyLinks(currentTrack || album, {
-            contribKey: 'coverArtistContribs',
-            dateKey: 'coverArtDate',
-            getThings: artist => [...artist.albumsAsCoverArtist, ...artist.tracksAsCoverArtist],
-            headingString: 'misc.chronology.heading.coverArt'
-        })
-    ].filter(Boolean).join('\n'));
+      generateChronologyLinks(currentTrack || album, {
+        contribKey: 'coverArtistContribs',
+        dateKey: 'coverArtDate',
+        getThings: (artist) => [
+          ...artist.albumsAsCoverArtist,
+          ...artist.tracksAsCoverArtist,
+        ],
+        headingString: 'misc.chronology.heading.coverArt',
+      }),
+    ]
+      .filter(Boolean)
+      .join('\n')
+  );
 }
diff --git a/src/page/artist-alias.js b/src/page/artist-alias.js
index ac23e902..3d882f65 100644
--- a/src/page/artist-alias.js
+++ b/src/page/artist-alias.js
@@ -1,22 +1,21 @@
+/** @format */
+
 // Artist alias redirect pages.
 // (Makes old permalinks bring visitors to the up-to-date page.)
 
 export function targets({wikiData}) {
-    return wikiData.artistAliasData;
+  return wikiData.artistAliasData;
 }
 
-export function write(aliasArtist, {wikiData}) {
-    // This function doesn't actually use wikiData, 8ut, um, consistency?
-
-    const { aliasedArtist } = aliasArtist;
+export function write(aliasArtist) {
+  const {aliasedArtist} = aliasArtist;
 
-    const redirect = {
-        type: 'redirect',
-        fromPath: ['artist', aliasArtist.directory],
-        toPath: ['artist', aliasedArtist.directory],
-        title: () => aliasedArtist.name
-    };
+  const redirect = {
+    type: 'redirect',
+    fromPath: ['artist', aliasArtist.directory],
+    toPath: ['artist', aliasedArtist.directory],
+    title: () => aliasedArtist.name,
+  };
 
-    return [redirect];
+  return [redirect];
 }
-
diff --git a/src/page/artist.js b/src/page/artist.js
index 6c31a010..481b4e36 100644
--- a/src/page/artist.js
+++ b/src/page/artist.js
@@ -1,3 +1,5 @@
+/** @format */
+
 // Artist page specification.
 //
 // NB: See artist-alias.js for artist alias redirect pages.
@@ -8,511 +10,749 @@ import fixWS from 'fix-whitespace';
 
 import * as html from '../util/html.js';
 
-import {
-    bindOpts,
-    unique
-} from '../util/sugar.js';
+import {bindOpts, unique} from '../util/sugar.js';
 
 import {
-    chunkByProperties,
-    getTotalDuration,
-    sortAlbumsTracksChronologically,
-    sortByDate,
-    sortByDirectory,
-    sortChronologically,
+  chunkByProperties,
+  getTotalDuration,
+  sortAlbumsTracksChronologically,
+  sortChronologically,
 } from '../util/wiki-data.js';
 
 // Page exports
 
 export function targets({wikiData}) {
-    return wikiData.artistData;
+  return wikiData.artistData;
 }
 
 export function write(artist, {wikiData}) {
-    const { groupData, wikiInfo } = wikiData;
-
-    const { name, urls, contextNotes } = artist;
-
-    const artThingsAll = sortAlbumsTracksChronologically(unique([
-        ...artist.albumsAsCoverArtist ?? [],
-        ...artist.albumsAsWallpaperArtist ?? [],
-        ...artist.albumsAsBannerArtist ?? [],
-        ...artist.tracksAsCoverArtist ?? []
-    ]), {getDate: o => o.coverArtDate});
-
-    const artThingsGallery = sortAlbumsTracksChronologically([
-        ...artist.albumsAsCoverArtist ?? [],
-        ...artist.tracksAsCoverArtist ?? []
-    ], {getDate: o => o.coverArtDate});
-
-    const commentaryThings = sortAlbumsTracksChronologically([
-        ...artist.albumsAsCommentator ?? [],
-        ...artist.tracksAsCommentator ?? []
-    ]);
-
-    const hasGallery = artThingsGallery.length > 0;
-
-    const getArtistsAndContrib = (thing, key) => ({
-        artists: thing[key]?.filter(({ who }) => who !== artist),
-        contrib: thing[key]?.find(({ who }) => who === artist),
-        thing,
-        key
-    });
-
-    const artListChunks = chunkByProperties(artThingsAll.flatMap(thing =>
-        (['coverArtistContribs', 'wallpaperArtistContribs', 'bannerArtistContribs']
-            .map(key => getArtistsAndContrib(thing, key))
-            .filter(({ contrib }) => contrib)
-            .map(props => ({
-                album: thing.album || thing,
-                track: thing.album ? thing : null,
-                date: thing.date,
-                ...props
-            })))
-    ), ['date', 'album']);
-
-    const commentaryListChunks = chunkByProperties(commentaryThings.map(thing => ({
-        album: thing.album || thing,
-        track: thing.album ? thing : null
-    })), ['album']);
-
-    const allTracks = sortAlbumsTracksChronologically(unique([
-        ...artist.tracksAsArtist ?? [],
-        ...artist.tracksAsContributor ?? []
-    ]));
-
-    const chunkTracks = tracks => (
-        chunkByProperties(tracks.map(track => ({
-            track,
-            date: +track.date,
-            album: track.album,
-            duration: track.duration,
-            artists: (track.artistContribs.some(({ who }) => who === artist)
-                ? track.artistContribs.filter(({ who }) => who !== artist)
-                : track.contributorContribs.filter(({ who }) => who !== artist)),
-            contrib: {
-                who: artist,
-                whatArray: [
-                    track.artistContribs.find(({ who }) => who === artist)?.what,
-                    track.contributorContribs.find(({ who }) => who === artist)?.what
-                ].filter(Boolean)
+  const {groupData, wikiInfo} = wikiData;
+
+  const {name, urls, contextNotes} = artist;
+
+  const artThingsAll = sortAlbumsTracksChronologically(
+    unique([
+      ...(artist.albumsAsCoverArtist ?? []),
+      ...(artist.albumsAsWallpaperArtist ?? []),
+      ...(artist.albumsAsBannerArtist ?? []),
+      ...(artist.tracksAsCoverArtist ?? []),
+    ]),
+    {getDate: (o) => o.coverArtDate}
+  );
+
+  const artThingsGallery = sortAlbumsTracksChronologically(
+    [
+      ...(artist.albumsAsCoverArtist ?? []),
+      ...(artist.tracksAsCoverArtist ?? []),
+    ],
+    {getDate: (o) => o.coverArtDate}
+  );
+
+  const commentaryThings = sortAlbumsTracksChronologically([
+    ...(artist.albumsAsCommentator ?? []),
+    ...(artist.tracksAsCommentator ?? []),
+  ]);
+
+  const hasGallery = artThingsGallery.length > 0;
+
+  const getArtistsAndContrib = (thing, key) => ({
+    artists: thing[key]?.filter(({who}) => who !== artist),
+    contrib: thing[key]?.find(({who}) => who === artist),
+    thing,
+    key,
+  });
+
+  const artListChunks = chunkByProperties(
+    artThingsAll.flatMap((thing) =>
+      ['coverArtistContribs', 'wallpaperArtistContribs', 'bannerArtistContribs']
+        .map((key) => getArtistsAndContrib(thing, key))
+        .filter(({contrib}) => contrib)
+        .map((props) => ({
+          album: thing.album || thing,
+          track: thing.album ? thing : null,
+          date: thing.date,
+          ...props,
+        }))
+    ),
+    ['date', 'album']
+  );
+
+  const commentaryListChunks = chunkByProperties(
+    commentaryThings.map((thing) => ({
+      album: thing.album || thing,
+      track: thing.album ? thing : null,
+    })),
+    ['album']
+  );
+
+  const allTracks = sortAlbumsTracksChronologically(
+    unique([
+      ...(artist.tracksAsArtist ?? []),
+      ...(artist.tracksAsContributor ?? []),
+    ])
+  );
+
+  const chunkTracks = (tracks) =>
+    chunkByProperties(
+      tracks.map((track) => ({
+        track,
+        date: +track.date,
+        album: track.album,
+        duration: track.duration,
+        artists: track.artistContribs.some(({who}) => who === artist)
+          ? track.artistContribs.filter(({who}) => who !== artist)
+          : track.contributorContribs.filter(({who}) => who !== artist),
+        contrib: {
+          who: artist,
+          whatArray: [
+            track.artistContribs.find(({who}) => who === artist)?.what,
+            track.contributorContribs.find(({who}) => who === artist)?.what,
+          ].filter(Boolean),
+        },
+      })),
+      ['date', 'album']
+    ).map(({date, album, chunk}) => ({
+      date,
+      album,
+      chunk,
+      duration: getTotalDuration(chunk),
+    }));
+
+  const trackListChunks = chunkTracks(allTracks);
+  const totalDuration = getTotalDuration(allTracks);
+
+  const countGroups = (things) => {
+    const usedGroups = things.flatMap(
+      (thing) => thing.groups || thing.album?.groups || []
+    );
+    return groupData
+      .map((group) => ({
+        group,
+        contributions: usedGroups.filter((g) => g === group).length,
+      }))
+      .filter(({contributions}) => contributions > 0)
+      .sort((a, b) => b.contributions - a.contributions);
+  };
+
+  const musicGroups = countGroups(allTracks);
+  const artGroups = countGroups(artThingsAll);
+
+  let flashes, flashListChunks;
+  if (wikiInfo.enableFlashesAndGames) {
+    flashes = sortChronologically(artist.flashesAsContributor?.slice() ?? []);
+    flashListChunks = chunkByProperties(
+      flashes.map((flash) => ({
+        act: flash.act,
+        flash,
+        date: flash.date,
+        // Manual artists/contrib properties here, 8ecause we don't
+        // want to show the full list of other contri8utors inline.
+        // (It can often 8e very, very large!)
+        artists: [],
+        contrib: flash.contributorContribs.find(({who}) => who === artist),
+      })),
+      ['act']
+    ).map(({act, chunk}) => ({
+      act,
+      chunk,
+      dateFirst: chunk[0].date,
+      dateLast: chunk[chunk.length - 1].date,
+    }));
+  }
+
+  const generateEntryAccents = ({
+    getArtistString,
+    language,
+    original,
+    entry,
+    artists,
+    contrib,
+  }) =>
+    original
+      ? language.$('artistPage.creditList.entry.rerelease', {entry})
+      : artists.length
+      ? contrib.what || contrib.whatArray?.length
+        ? language.$(
+            'artistPage.creditList.entry.withArtists.withContribution',
+            {
+              entry,
+              artists: getArtistString(artists),
+              contribution: contrib.whatArray
+                ? language.formatUnitList(contrib.whatArray)
+                : contrib.what,
             }
-        })), ['date', 'album'])
-        .map(({date, album, chunk}) => ({
-            date, album, chunk,
-            duration: getTotalDuration(chunk),
-        })));
-
-    const trackListChunks = chunkTracks(allTracks);
-    const totalDuration = getTotalDuration(allTracks);
-
-    const countGroups = things => {
-        const usedGroups = things.flatMap(thing => thing.groups || thing.album?.groups || []);
-        return groupData
-            .map(group => ({
-                group,
-                contributions: usedGroups.filter(g => g === group).length
-            }))
-            .filter(({ contributions }) => contributions > 0)
-            .sort((a, b) => b.contributions - a.contributions);
-    };
+          )
+        : 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 musicGroups = countGroups(allTracks);
-    const artGroups = countGroups(artThingsAll);
-
-    let flashes, flashListChunks;
-    if (wikiInfo.enableFlashesAndGames) {
-        flashes = sortChronologically(artist.flashesAsContributor?.slice() ?? []);
-        flashListChunks = (
-            chunkByProperties(flashes.map(flash => ({
-                act: flash.act,
-                flash,
-                date: flash.date,
-                // Manual artists/contrib properties here, 8ecause we don't
-                // want to show the full list of other contri8utors inline.
-                // (It can often 8e very, very large!)
-                artists: [],
-                contrib: flash.contributorContribs.find(({ who }) => who === artist)
-            })), ['act'])
-            .map(({ act, chunk }) => ({
-                act, chunk,
-                dateFirst: chunk[0].date,
-                dateLast: chunk[chunk.length - 1].date
-            })));
-    }
-
-    const generateEntryAccents = ({
-        getArtistString, language,
-        original, entry, artists, contrib
-    }) =>
-        (original
-            ? language.$('artistPage.creditList.entry.rerelease', {entry})
-            : (artists.length
-                ? ((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, link, language
-    }) => fixWS`
+  const unbound_generateTrackList = (
+    chunks,
+    {getArtistString, link, language}
+  ) => fixWS`
         <dl>
-            ${chunks.map(({date, album, chunk, duration}) => fixWS`
+            ${chunks
+              .map(
+                ({date, album, chunk, duration}) => fixWS`
                 <dt>${
-                    (date && duration) ? language.$('artistPage.creditList.album.withDate.withDuration', {
+                  date && duration
+                    ? language.$(
+                        'artistPage.creditList.album.withDate.withDuration',
+                        {
+                          album: link.album(album),
+                          date: language.formatDate(date),
+                          duration: language.formatDuration(duration, {
+                            approximate: true,
+                          }),
+                        }
+                      )
+                    : date
+                    ? language.$('artistPage.creditList.album.withDate', {
                         album: link.album(album),
                         date: language.formatDate(date),
-                        duration: language.formatDuration(duration, {approximate: true})
-                    }) : date ? language.$('artistPage.creditList.album.withDate', {
+                      })
+                    : duration
+                    ? language.$('artistPage.creditList.album.withDuration', {
                         album: link.album(album),
-                        date: language.formatDate(date)
-                    }) : duration ? language.$('artistPage.creditList.album.withDuration', {
+                        duration: language.formatDuration(duration, {
+                          approximate: true,
+                        }),
+                      })
+                    : language.$('artistPage.creditList.album', {
                         album: link.album(album),
-                        duration: language.formatDuration(duration, {approximate: true})
-                    }) : language.$('artistPage.creditList.album', {
-                        album: link.album(album)
-                    })}</dt>
+                      })
+                }</dt>
                 <dd><ul>
-                    ${(chunk
-                        .map(({track, ...props}) => ({
-                            original: track.originalReleaseTrack,
-                            entry: language.$('artistPage.creditList.entry.track.withDuration', {
-                                track: link.track(track),
-                                duration: language.formatDuration(track.duration ?? 0)
-                            }),
-                            ...props
-                        }))
-                        .map(({original, ...opts}) => html.tag('li',
-                            {class: original && 'rerelease'},
-                            generateEntryAccents({getArtistString, language, original, ...opts})))
-                        .join('\n'))}
+                    ${chunk
+                      .map(({track, ...props}) => ({
+                        original: track.originalReleaseTrack,
+                        entry: language.$(
+                          'artistPage.creditList.entry.track.withDuration',
+                          {
+                            track: link.track(track),
+                            duration: language.formatDuration(
+                              track.duration ?? 0
+                            ),
+                          }
+                        ),
+                        ...props,
+                      }))
+                      .map(({original, ...opts}) =>
+                        html.tag(
+                          'li',
+                          {class: original && 'rerelease'},
+                          generateEntryAccents({
+                            getArtistString,
+                            language,
+                            original,
+                            ...opts,
+                          })
+                        )
+                      )
+                      .join('\n')}
                 </ul></dd>
-            `).join('\n')}
+            `
+              )
+              .join('\n')}
         </dl>
     `;
 
-    const unbound_serializeArtistsAndContrib = (key, {
-        serializeContribs,
-        serializeLink
-    }) => thing => {
-        const { artists, contrib } = getArtistsAndContrib(thing, key);
-        const ret = {};
-        ret.link = serializeLink(thing);
-        if (contrib.what) ret.contribution = contrib.what;
-        if (artists.length) ret.otherArtists = serializeContribs(artists);
-        return ret;
+  const unbound_serializeArtistsAndContrib =
+    (key, {serializeContribs, serializeLink}) =>
+    (thing) => {
+      const {artists, contrib} = getArtistsAndContrib(thing, key);
+      const ret = {};
+      ret.link = serializeLink(thing);
+      if (contrib.what) ret.contribution = contrib.what;
+      if (artists.length) ret.otherArtists = serializeContribs(artists);
+      return ret;
     };
 
-    const unbound_serializeTrackListChunks = (chunks, {serializeLink}) =>
-        chunks.map(({date, album, chunk, duration}) => ({
-            album: serializeLink(album),
-            date,
-            duration,
-            tracks: chunk.map(({ track }) => ({
-                link: serializeLink(track),
-                duration: track.duration
-            }))
-        }));
-
-    const data = {
-        type: 'data',
-        path: ['artist', artist.directory],
-        data: ({
-            serializeContribs,
-            serializeLink
-        }) => {
-            const serializeArtistsAndContrib = bindOpts(unbound_serializeArtistsAndContrib, {
-                serializeContribs,
-                serializeLink
-            });
-
-            const serializeTrackListChunks = bindOpts(unbound_serializeTrackListChunks, {
-                serializeLink
-            });
-
-            return {
-                albums: {
-                    asCoverArtist: artist.albumsAsCoverArtist?.map(serializeArtistsAndContrib('coverArtistContribs')),
-                    asWallpaperArtist: artist.albumsAsWallpaperArtist?.map(serializeArtistsAndContrib('wallpaperArtistContribs')),
-                    asBannerArtist: artist.albumsAsBannerArtist?.map(serializeArtistsAndContrib('bannerArtistContribs'))
-                },
-                flashes: wikiInfo.enableFlashesAndGames ? {
-                    asContributor: (artist.flashesAsContributor
-                        ?.map(flash => getArtistsAndContrib(flash, 'contributorContribs'))
-                        .map(({ contrib, thing: flash }) => ({
-                            link: serializeLink(flash),
-                            contribution: contrib.what
-                        })))
-                } : null,
-                tracks: {
-                    asArtist: artist.tracksAsArtist.map(serializeArtistsAndContrib('artistContribs')),
-                    asContributor: artist.tracksAsContributor.map(serializeArtistsAndContrib('contributorContribs')),
-                    chunked: serializeTrackListChunks(trackListChunks)
-                }
-            };
+  const unbound_serializeTrackListChunks = (chunks, {serializeLink}) =>
+    chunks.map(({date, album, chunk, duration}) => ({
+      album: serializeLink(album),
+      date,
+      duration,
+      tracks: chunk.map(({track}) => ({
+        link: serializeLink(track),
+        duration: track.duration,
+      })),
+    }));
+
+  const data = {
+    type: 'data',
+    path: ['artist', artist.directory],
+    data: ({serializeContribs, serializeLink}) => {
+      const serializeArtistsAndContrib = bindOpts(
+        unbound_serializeArtistsAndContrib,
+        {
+          serializeContribs,
+          serializeLink,
         }
-    };
+      );
 
-    const infoPage = {
-        type: 'page',
-        path: ['artist', artist.directory],
-        page: ({
-            fancifyURL,
-            generateCoverLink,
-            generateInfoGalleryLinks,
-            getArtistAvatar,
-            getArtistString,
-            link,
-            language,
-            to,
-            transformMultiline
-        }) => {
-            const generateTrackList = bindOpts(unbound_generateTrackList, {
-                getArtistString,
-                link,
-                language
-            });
-
-            return {
-                title: language.$('artistPage.title', {artist: name}),
-
-                main: {
-                    content: fixWS`
-                        ${artist.hasAvatar && generateCoverLink({
+      const serializeTrackListChunks = bindOpts(
+        unbound_serializeTrackListChunks,
+        {
+          serializeLink,
+        }
+      );
+
+      return {
+        albums: {
+          asCoverArtist: artist.albumsAsCoverArtist?.map(
+            serializeArtistsAndContrib('coverArtistContribs')
+          ),
+          asWallpaperArtist: artist.albumsAsWallpaperArtist?.map(
+            serializeArtistsAndContrib('wallpaperArtistContribs')
+          ),
+          asBannerArtist: artist.albumsAsBannerArtist?.map(
+            serializeArtistsAndContrib('bannerArtistContribs')
+          ),
+        },
+        flashes: wikiInfo.enableFlashesAndGames
+          ? {
+              asContributor: artist.flashesAsContributor
+                ?.map((flash) =>
+                  getArtistsAndContrib(flash, 'contributorContribs')
+                )
+                .map(({contrib, thing: flash}) => ({
+                  link: serializeLink(flash),
+                  contribution: contrib.what,
+                })),
+            }
+          : null,
+        tracks: {
+          asArtist: artist.tracksAsArtist.map(
+            serializeArtistsAndContrib('artistContribs')
+          ),
+          asContributor: artist.tracksAsContributor.map(
+            serializeArtistsAndContrib('contributorContribs')
+          ),
+          chunked: serializeTrackListChunks(trackListChunks),
+        },
+      };
+    },
+  };
+
+  const infoPage = {
+    type: 'page',
+    path: ['artist', artist.directory],
+    page: ({
+      fancifyURL,
+      generateCoverLink,
+      generateInfoGalleryLinks,
+      getArtistAvatar,
+      getArtistString,
+      link,
+      language,
+      transformMultiline,
+    }) => {
+      const generateTrackList = bindOpts(unbound_generateTrackList, {
+        getArtistString,
+        link,
+        language,
+      });
+
+      return {
+        title: language.$('artistPage.title', {artist: name}),
+
+        main: {
+          content: fixWS`
+                        ${
+                          artist.hasAvatar &&
+                          generateCoverLink({
                             src: getArtistAvatar(artist),
-                            alt: language.$('misc.alt.artistAvatar')
-                        })}
-                        <h1>${language.$('artistPage.title', {artist: name})}</h1>
-                        ${contextNotes && fixWS`
+                            alt: language.$('misc.alt.artistAvatar'),
+                          })
+                        }
+                        <h1>${language.$('artistPage.title', {
+                          artist: name,
+                        })}</h1>
+                        ${
+                          contextNotes &&
+                          fixWS`
                             <p>${language.$('releaseInfo.note')}</p>
                             <blockquote>
                                 ${transformMultiline(contextNotes)}
                             </blockquote>
                             <hr>
-                        `}
-                        ${urls?.length && `<p>${language.$('releaseInfo.visitOn', {
-                            links: language.formatDisjunctionList(urls.map(url => fancifyURL(url, {language})))
-                        })}</p>`}
-                        ${hasGallery && `<p>${language.$('artistPage.viewArtGallery', {
+                        `
+                        }
+                        ${
+                          urls?.length &&
+                          `<p>${language.$('releaseInfo.visitOn', {
+                            links: language.formatDisjunctionList(
+                              urls.map((url) => fancifyURL(url, {language}))
+                            ),
+                          })}</p>`
+                        }
+                        ${
+                          hasGallery &&
+                          `<p>${language.$('artistPage.viewArtGallery', {
                             link: link.artistGallery(artist, {
-                                text: language.$('artistPage.viewArtGallery.link')
-                            })
-                        })}</p>`}
+                              text: language.$(
+                                'artistPage.viewArtGallery.link'
+                              ),
+                            }),
+                          })}</p>`
+                        }
                         <p>${language.$('misc.jumpTo.withLinks', {
-                            links: language.formatUnitList([
-                                allTracks.length && `<a href="#tracks">${language.$('artistPage.trackList.title')}</a>`,
-                                artThingsAll.length && `<a href="#art">${language.$('artistPage.artList.title')}</a>`,
-                                wikiInfo.enableFlashesAndGames && flashes.length && `<a href="#flashes">${language.$('artistPage.flashList.title')}</a>`,
-                                commentaryThings.length && `<a href="#commentary">${language.$('artistPage.commentaryList.title')}</a>`
-                            ].filter(Boolean))
+                          links: language.formatUnitList(
+                            [
+                              allTracks.length &&
+                                `<a href="#tracks">${language.$(
+                                  'artistPage.trackList.title'
+                                )}</a>`,
+                              artThingsAll.length &&
+                                `<a href="#art">${language.$(
+                                  'artistPage.artList.title'
+                                )}</a>`,
+                              wikiInfo.enableFlashesAndGames &&
+                                flashes.length &&
+                                `<a href="#flashes">${language.$(
+                                  'artistPage.flashList.title'
+                                )}</a>`,
+                              commentaryThings.length &&
+                                `<a href="#commentary">${language.$(
+                                  'artistPage.commentaryList.title'
+                                )}</a>`,
+                            ].filter(Boolean)
+                          ),
                         })}</p>
-                        ${allTracks.length && fixWS`
-                            <h2 id="tracks">${language.$('artistPage.trackList.title')}</h2>
-                            <p>${language.$('artistPage.contributedDurationLine', {
+                        ${
+                          allTracks.length &&
+                          fixWS`
+                            <h2 id="tracks">${language.$(
+                              'artistPage.trackList.title'
+                            )}</h2>
+                            <p>${language.$(
+                              'artistPage.contributedDurationLine',
+                              {
                                 artist: artist.name,
-                                duration: language.formatDuration(totalDuration, {approximate: true, unit: true})
-                            })}</p>
+                                duration: language.formatDuration(
+                                  totalDuration,
+                                  {
+                                    approximate: true,
+                                    unit: true,
+                                  }
+                                ),
+                              }
+                            )}</p>
                             <p>${language.$('artistPage.musicGroupsLine', {
-                                groups: language.formatUnitList(musicGroups
-                                    .map(({ group, contributions }) => language.$('artistPage.groupsLine.item', {
-                                        group: link.groupInfo(group),
-                                        contributions: language.countContributions(contributions)
-                                    })))
+                              groups: language.formatUnitList(
+                                musicGroups.map(({group, contributions}) =>
+                                  language.$('artistPage.groupsLine.item', {
+                                    group: link.groupInfo(group),
+                                    contributions:
+                                      language.countContributions(
+                                        contributions
+                                      ),
+                                  })
+                                )
+                              ),
                             })}</p>
                             ${generateTrackList(trackListChunks)}
-                        `}
-                        ${artThingsAll.length && fixWS`
-                            <h2 id="art">${language.$('artistPage.artList.title')}</h2>
-                            ${hasGallery && `<p>${language.$('artistPage.viewArtGallery.orBrowseList', {
-                                link: link.artistGallery(artist, {
-                                    text: language.$('artistPage.viewArtGallery.link')
-                                })
-                            })}</p>`}
+                        `
+                        }
+                        ${
+                          artThingsAll.length &&
+                          fixWS`
+                            <h2 id="art">${language.$(
+                              'artistPage.artList.title'
+                            )}</h2>
+                            ${
+                              hasGallery &&
+                              `<p>${language.$(
+                                'artistPage.viewArtGallery.orBrowseList',
+                                {
+                                  link: link.artistGallery(artist, {
+                                    text: language.$(
+                                      'artistPage.viewArtGallery.link'
+                                    ),
+                                  }),
+                                }
+                              )}</p>`
+                            }
                             <p>${language.$('artistPage.artGroupsLine', {
-                                groups: language.formatUnitList(artGroups
-                                    .map(({ group, contributions }) => language.$('artistPage.groupsLine.item', {
-                                        group: link.groupInfo(group),
-                                        contributions: language.countContributions(contributions)
-                                    })))
+                              groups: language.formatUnitList(
+                                artGroups.map(({group, contributions}) =>
+                                  language.$('artistPage.groupsLine.item', {
+                                    group: link.groupInfo(group),
+                                    contributions:
+                                      language.countContributions(
+                                        contributions
+                                      ),
+                                  })
+                                )
+                              ),
                             })}</p>
                             <dl>
-                                ${artListChunks.map(({date, album, chunk}) => fixWS`
-                                    <dt>${language.$('artistPage.creditList.album.withDate', {
+                                ${artListChunks
+                                  .map(
+                                    ({date, album, chunk}) => fixWS`
+                                    <dt>${language.$(
+                                      'artistPage.creditList.album.withDate',
+                                      {
                                         album: link.album(album),
-                                        date: language.formatDate(date)
-                                    })}</dt>
+                                        date: language.formatDate(date),
+                                      }
+                                    )}</dt>
                                     <dd><ul>
-                                        ${(chunk
-                                            .map(({album, track, key, ...props}) => ({
-                                                entry: (track
-                                                    ? language.$('artistPage.creditList.entry.track', {
-                                                        track: link.track(track)
-                                                    })
-                                                    : `<i>${language.$('artistPage.creditList.entry.album.' + {
-                                                        wallpaperArtistContribs: 'wallpaperArt',
-                                                        bannerArtistContribs: 'bannerArt',
-                                                        coverArtistContribs: 'coverArt'
-                                                    }[key])}</i>`),
-                                                ...props
-                                            }))
-                                            .map(opts => generateEntryAccents({getArtistString, language, ...opts}))
-                                            .map(row => `<li>${row}</li>`)
-                                            .join('\n'))}
+                                        ${chunk
+                                          .map(
+                                            ({
+                                              track,
+                                              key,
+                                              ...props
+                                            }) => ({
+                                              entry: track
+                                                ? language.$(
+                                                    'artistPage.creditList.entry.track',
+                                                    {
+                                                      track: link.track(track),
+                                                    }
+                                                  )
+                                                : `<i>${language.$(
+                                                    'artistPage.creditList.entry.album.' +
+                                                      {
+                                                        wallpaperArtistContribs:
+                                                          'wallpaperArt',
+                                                        bannerArtistContribs:
+                                                          'bannerArt',
+                                                        coverArtistContribs:
+                                                          'coverArt',
+                                                      }[key]
+                                                  )}</i>`,
+                                              ...props,
+                                            })
+                                          )
+                                          .map((opts) =>
+                                            generateEntryAccents({
+                                              getArtistString,
+                                              language,
+                                              ...opts,
+                                            })
+                                          )
+                                          .map((row) => `<li>${row}</li>`)
+                                          .join('\n')}
                                     </ul></dd>
-                                `).join('\n')}
+                                `
+                                  )
+                                  .join('\n')}
                             </dl>
-                        `}
-                        ${wikiInfo.enableFlashesAndGames && flashes.length && fixWS`
-                            <h2 id="flashes">${language.$('artistPage.flashList.title')}</h2>
+                        `
+                        }
+                        ${
+                          wikiInfo.enableFlashesAndGames &&
+                          flashes.length &&
+                          fixWS`
+                            <h2 id="flashes">${language.$(
+                              'artistPage.flashList.title'
+                            )}</h2>
                             <dl>
-                                ${flashListChunks.map(({act, chunk, dateFirst, dateLast}) => fixWS`
-                                    <dt>${language.$('artistPage.creditList.flashAct.withDateRange', {
-                                        act: link.flash(chunk[0].flash, {text: act.name}),
-                                        dateRange: language.formatDateRange(dateFirst, dateLast)
-                                    })}</dt>
+                                ${flashListChunks
+                                  .map(
+                                    ({
+                                      act,
+                                      chunk,
+                                      dateFirst,
+                                      dateLast,
+                                    }) => fixWS`
+                                    <dt>${language.$(
+                                      'artistPage.creditList.flashAct.withDateRange',
+                                      {
+                                        act: link.flash(chunk[0].flash, {
+                                          text: act.name,
+                                        }),
+                                        dateRange: language.formatDateRange(
+                                          dateFirst,
+                                          dateLast
+                                        ),
+                                      }
+                                    )}</dt>
                                     <dd><ul>
-                                        ${(chunk
-                                            .map(({flash, ...props}) => ({
-                                                entry: language.$('artistPage.creditList.entry.flash', {
-                                                    flash: link.flash(flash)
-                                                }),
-                                                ...props
-                                            }))
-                                            .map(opts => generateEntryAccents({getArtistString, language, ...opts}))
-                                            .map(row => `<li>${row}</li>`)
-                                            .join('\n'))}
+                                        ${chunk
+                                          .map(({flash, ...props}) => ({
+                                            entry: language.$(
+                                              'artistPage.creditList.entry.flash',
+                                              {
+                                                flash: link.flash(flash),
+                                              }
+                                            ),
+                                            ...props,
+                                          }))
+                                          .map((opts) =>
+                                            generateEntryAccents({
+                                              getArtistString,
+                                              language,
+                                              ...opts,
+                                            })
+                                          )
+                                          .map((row) => `<li>${row}</li>`)
+                                          .join('\n')}
                                     </ul></dd>
-                                `).join('\n')}
+                                `
+                                  )
+                                  .join('\n')}
                             </dl>
-                        `}
-                        ${commentaryThings.length && fixWS`
-                            <h2 id="commentary">${language.$('artistPage.commentaryList.title')}</h2>
+                        `
+                        }
+                        ${
+                          commentaryThings.length &&
+                          fixWS`
+                            <h2 id="commentary">${language.$(
+                              'artistPage.commentaryList.title'
+                            )}</h2>
                             <dl>
-                                ${commentaryListChunks.map(({album, chunk}) => fixWS`
-                                    <dt>${language.$('artistPage.creditList.album', {
-                                        album: link.album(album)
-                                    })}</dt>
+                                ${commentaryListChunks
+                                  .map(
+                                    ({album, chunk}) => fixWS`
+                                    <dt>${language.$(
+                                      'artistPage.creditList.album',
+                                      {
+                                        album: link.album(album),
+                                      }
+                                    )}</dt>
                                     <dd><ul>
-                                        ${(chunk
-                                            .map(({album, track, ...props}) => track
-                                                ? language.$('artistPage.creditList.entry.track', {
-                                                    track: link.track(track)
-                                                })
-                                                : `<i>${language.$('artistPage.creditList.entry.album.commentary')}</i>`)
-                                            .map(row => `<li>${row}</li>`)
-                                            .join('\n'))}
+                                        ${chunk
+                                          .map(({track}) =>
+                                            track
+                                              ? language.$(
+                                                  'artistPage.creditList.entry.track',
+                                                  {
+                                                    track: link.track(track),
+                                                  }
+                                                )
+                                              : `<i>${language.$(
+                                                  'artistPage.creditList.entry.album.commentary'
+                                                )}</i>`
+                                          )
+                                          .map((row) => `<li>${row}</li>`)
+                                          .join('\n')}
                                     </ul></dd>
-                                `).join('\n')}
+                                `
+                                  )
+                                  .join('\n')}
                             </dl>
-                        `}
-                    `
-                },
-
-                nav: generateNavForArtist(artist, false, hasGallery, {
-                    generateInfoGalleryLinks,
-                    link,
-                    language,
-                    wikiData
-                })
-            };
-        }
-    };
-
-    const galleryPage = hasGallery && {
-        type: 'page',
-        path: ['artistGallery', artist.directory],
-        page: ({
-            generateInfoGalleryLinks,
-            getAlbumCover,
-            getGridHTML,
-            getTrackCover,
-            link,
-            language,
-            to
-        }) => ({
-            title: language.$('artistGalleryPage.title', {artist: name}),
-
-            main: {
-                classes: ['top-index'],
-                content: fixWS`
-                    <h1>${language.$('artistGalleryPage.title', {artist: name})}</h1>
-                    <p class="quick-info">${language.$('artistGalleryPage.infoLine', {
-                        coverArts: language.countCoverArts(artThingsGallery.length, {unit: true})
-                    })}</p>
+                        `
+                        }
+                    `,
+        },
+
+        nav: generateNavForArtist(artist, false, hasGallery, {
+          generateInfoGalleryLinks,
+          link,
+          language,
+          wikiData,
+        }),
+      };
+    },
+  };
+
+  const galleryPage = hasGallery && {
+    type: 'page',
+    path: ['artistGallery', artist.directory],
+    page: ({
+      generateInfoGalleryLinks,
+      getAlbumCover,
+      getGridHTML,
+      getTrackCover,
+      link,
+      language,
+    }) => ({
+      title: language.$('artistGalleryPage.title', {artist: name}),
+
+      main: {
+        classes: ['top-index'],
+        content: fixWS`
+                    <h1>${language.$('artistGalleryPage.title', {
+                      artist: name,
+                    })}</h1>
+                    <p class="quick-info">${language.$(
+                      'artistGalleryPage.infoLine',
+                      {
+                        coverArts: language.countCoverArts(
+                          artThingsGallery.length,
+                          {
+                            unit: true,
+                          }
+                        ),
+                      }
+                    )}</p>
                     <div class="grid-listing">
                         ${getGridHTML({
-                            entries: artThingsGallery.map(item => ({item})),
-                            srcFn: thing => (thing.album
-                                ? getTrackCover(thing)
-                                : getAlbumCover(thing)),
-                            linkFn: (thing, opts) => (thing.album
-                                ? link.track(thing, opts)
-                                : link.album(thing, opts))
+                          entries: artThingsGallery.map((item) => ({item})),
+                          srcFn: (thing) =>
+                            thing.album
+                              ? getTrackCover(thing)
+                              : getAlbumCover(thing),
+                          linkFn: (thing, opts) =>
+                            thing.album
+                              ? link.track(thing, opts)
+                              : link.album(thing, opts),
                         })}
                     </div>
-                `
-            },
-
-            nav: generateNavForArtist(artist, true, hasGallery, {
-                generateInfoGalleryLinks,
-                link,
-                language,
-                wikiData
-            })
-        })
-    };
-
-    return [data, infoPage, galleryPage].filter(Boolean);
+                `,
+      },
+
+      nav: generateNavForArtist(artist, true, hasGallery, {
+        generateInfoGalleryLinks,
+        link,
+        language,
+        wikiData,
+      }),
+    }),
+  };
+
+  return [data, infoPage, galleryPage].filter(Boolean);
 }
 
 // Utility functions
 
-function generateNavForArtist(artist, isGallery, hasGallery, {
-    generateInfoGalleryLinks,
-    link,
-    language,
-    wikiData
-}) {
-    const { wikiInfo } = wikiData;
-
-    const infoGalleryLinks = (hasGallery &&
-        generateInfoGalleryLinks(artist, isGallery, {
-            link, language,
-            linkKeyGallery: 'artistGallery',
-            linkKeyInfo: 'artist'
-        }))
+function generateNavForArtist(
+  artist,
+  isGallery,
+  hasGallery,
+  {generateInfoGalleryLinks, link, language, wikiData}
+) {
+  const {wikiInfo} = wikiData;
+
+  const infoGalleryLinks =
+    hasGallery &&
+    generateInfoGalleryLinks(artist, isGallery, {
+      link,
+      language,
+      linkKeyGallery: 'artistGallery',
+      linkKeyInfo: 'artist',
+    });
 
-    return {
-        linkContainerClasses: ['nav-links-hierarchy'],
-        links: [
-            {toHome: true},
-            wikiInfo.enableListings &&
-            {
-                path: ['localized.listingIndex'],
-                title: language.$('listingIndex.title')
-            },
-            {
-                html: language.$('artistPage.nav.artist', {
-                    artist: link.artist(artist, {class: 'current'})
-                })
-            },
-            hasGallery &&
-            {
-                divider: false,
-                html: `(${infoGalleryLinks})`
-            }
-        ]
-    };
+  return {
+    linkContainerClasses: ['nav-links-hierarchy'],
+    links: [
+      {toHome: true},
+      wikiInfo.enableListings && {
+        path: ['localized.listingIndex'],
+        title: language.$('listingIndex.title'),
+      },
+      {
+        html: language.$('artistPage.nav.artist', {
+          artist: link.artist(artist, {class: 'current'}),
+        }),
+      },
+      hasGallery && {
+        divider: false,
+        html: `(${infoGalleryLinks})`,
+      },
+    ],
+  };
 }
diff --git a/src/page/flash.js b/src/page/flash.js
index 21a22b94..a4b3b9b0 100644
--- a/src/page/flash.js
+++ b/src/page/flash.js
@@ -1,3 +1,5 @@
+/** @format */
+
 // Flash page and index specifications.
 
 // Imports
@@ -6,247 +8,318 @@ import fixWS from 'fix-whitespace';
 
 import * as html from '../util/html.js';
 
-import {
-    getFlashLink
-} from '../util/wiki-data.js';
+import {getFlashLink} from '../util/wiki-data.js';
 
 // Page exports
 
 export function condition({wikiData}) {
-    return wikiData.wikiInfo.enableFlashesAndGames;
+  return wikiData.wikiInfo.enableFlashesAndGames;
 }
 
 export function targets({wikiData}) {
-    return wikiData.flashData;
+  return wikiData.flashData;
 }
 
 export function write(flash, {wikiData}) {
-    const page = {
-        type: 'page',
-        path: ['flash', flash.directory],
-        page: ({
-            fancifyFlashURL,
-            generateChronologyLinks,
-            generateCoverLink,
-            generatePreviousNextLinks,
-            getArtistString,
-            getFlashCover,
-            getThemeString,
-            link,
-            language,
-            transformInline
-        }) => ({
-            title: language.$('flashPage.title', {flash: flash.name}),
-            theme: getThemeString(flash.color, [
-                `--flash-directory: ${flash.directory}`
-            ]),
-
-            main: {
-                content: fixWS`
-                    <h1>${language.$('flashPage.title', {flash: flash.name})}</h1>
+  const page = {
+    type: 'page',
+    path: ['flash', flash.directory],
+    page: ({
+      fancifyFlashURL,
+      generateChronologyLinks,
+      generateCoverLink,
+      generatePreviousNextLinks,
+      getArtistString,
+      getFlashCover,
+      getThemeString,
+      link,
+      language,
+    }) => ({
+      title: language.$('flashPage.title', {flash: flash.name}),
+      theme: getThemeString(flash.color, [
+        `--flash-directory: ${flash.directory}`,
+      ]),
+
+      main: {
+        content: fixWS`
+                    <h1>${language.$('flashPage.title', {
+                      flash: flash.name,
+                    })}</h1>
                     ${generateCoverLink({
-                        src: getFlashCover(flash),
-                        alt: language.$('misc.alt.flashArt')
+                      src: getFlashCover(flash),
+                      alt: language.$('misc.alt.flashArt'),
                     })}
-                    <p>${language.$('releaseInfo.released', {date: language.formatDate(flash.date)})}</p>
-                    ${(flash.page || flash.urls?.length) && `<p>${language.$('releaseInfo.playOn', {
-                        links: language.formatDisjunctionList([
+                    <p>${language.$('releaseInfo.released', {
+                      date: language.formatDate(flash.date),
+                    })}</p>
+                    ${
+                      (flash.page || flash.urls?.length) &&
+                      `<p>${language.$('releaseInfo.playOn', {
+                        links: language.formatDisjunctionList(
+                          [
                             flash.page && getFlashLink(flash),
-                            ...flash.urls ?? []
-                        ].map(url => fancifyFlashURL(url, flash)))
-                    })}</p>`}
-                    ${flash.featuredTracks && fixWS`
-                        <p>Tracks featured in <i>${flash.name.replace(/\.$/, '')}</i>:</p>
+                            ...(flash.urls ?? []),
+                          ].map((url) => fancifyFlashURL(url, flash))
+                        ),
+                      })}</p>`
+                    }
+                    ${
+                      flash.featuredTracks &&
+                      fixWS`
+                        <p>Tracks featured in <i>${flash.name.replace(
+                          /\.$/,
+                          ''
+                        )}</i>:</p>
                         <ul>
-                            ${(flash.featuredTracks
-                                .map(track => language.$('trackList.item.withArtists', {
-                                    track: link.track(track),
-                                    by: `<span class="by">${
-                                        language.$('trackList.item.withArtists.by', {
-                                            artists: getArtistString(track.artistContribs)
-                                        })
-                                    }</span>`
-                                }))
-                                .map(row => `<li>${row}</li>`)
-                                .join('\n'))}
+                            ${flash.featuredTracks
+                              .map((track) =>
+                                language.$('trackList.item.withArtists', {
+                                  track: link.track(track),
+                                  by: `<span class="by">${language.$(
+                                    'trackList.item.withArtists.by',
+                                    {
+                                      artists: getArtistString(
+                                        track.artistContribs
+                                      ),
+                                    }
+                                  )}</span>`,
+                                })
+                              )
+                              .map((row) => `<li>${row}</li>`)
+                              .join('\n')}
                         </ul>
-                    `}
-                    ${flash.contributorContribs.length && fixWS`
+                    `
+                    }
+                    ${
+                      flash.contributorContribs.length &&
+                      fixWS`
                         <p>${language.$('releaseInfo.contributors')}</p>
                         <ul>
                             ${flash.contributorContribs
-                                .map(contrib => `<li>${getArtistString([contrib], {
+                              .map(
+                                (contrib) =>
+                                  `<li>${getArtistString([contrib], {
                                     showContrib: true,
-                                    showIcons: true
-                                })}</li>`)
-                                .join('\n')}
+                                    showIcons: true,
+                                  })}</li>`
+                              )
+                              .join('\n')}
                         </ul>
-                    `}
-                `
-            },
-
-            sidebarLeft: generateSidebarForFlash(flash, {link, language, wikiData}),
-            nav: generateNavForFlash(flash, {
-                generateChronologyLinks,
-                generatePreviousNextLinks,
-                link,
-                language,
-                wikiData
-            })
-        })
-    };
-
-    return [page];
+                    `
+                    }
+                `,
+      },
+
+      sidebarLeft: generateSidebarForFlash(flash, {link, language, wikiData}),
+      nav: generateNavForFlash(flash, {
+        generateChronologyLinks,
+        generatePreviousNextLinks,
+        link,
+        language,
+        wikiData,
+      }),
+    }),
+  };
+
+  return [page];
 }
 
 export function writeTargetless({wikiData}) {
-    const { flashActData } = wikiData;
-
-    const page = {
-        type: 'page',
-        path: ['flashIndex'],
-        page: ({
-            getFlashGridHTML,
-            getLinkThemeString,
-            link,
-            language
-        }) => ({
-            title: language.$('flashIndex.title'),
-
-            main: {
-                classes: ['flash-index'],
-                content: fixWS`
+  const {flashActData} = wikiData;
+
+  const page = {
+    type: 'page',
+    path: ['flashIndex'],
+    page: ({getFlashGridHTML, getLinkThemeString, link, language}) => ({
+      title: language.$('flashIndex.title'),
+
+      main: {
+        classes: ['flash-index'],
+        content: fixWS`
                     <h1>${language.$('flashIndex.title')}</h1>
                     <div class="long-content">
                         <p class="quick-info">${language.$('misc.jumpTo')}</p>
                         <ul class="quick-info">
-                            ${flashActData.filter(act => act.jump).map(({ anchor, jump, jumpColor }) => fixWS`
-                                <li><a href="#${anchor}" style="${getLinkThemeString(jumpColor)}">${jump}</a></li>
-                            `).join('\n')}
+                            ${flashActData
+                              .filter((act) => act.jump)
+                              .map(
+                                ({anchor, jump, jumpColor}) => fixWS`
+                                <li><a href="#${anchor}" style="${getLinkThemeString(
+                                  jumpColor
+                                )}">${jump}</a></li>
+                            `
+                              )
+                              .join('\n')}
                         </ul>
                     </div>
-                    ${flashActData.map((act, i) => fixWS`
-                        <h2 id="${act.anchor}" style="${getLinkThemeString(act.color)}">${link.flash(act.flashes[0], {text: act.name})}</h2>
+                    ${flashActData
+                      .map(
+                        (act, i) => fixWS`
+                        <h2 id="${act.anchor}" style="${getLinkThemeString(
+                          act.color
+                        )}">${link.flash(act.flashes[0], {
+                          text: act.name,
+                        })}</h2>
                         <div class="grid-listing">
                             ${getFlashGridHTML({
-                                entries: act.flashes.map(flash => ({item: flash})),
-                                lazy: i === 0 ? 4 : true
+                              entries: act.flashes.map((flash) => ({
+                                item: flash,
+                              })),
+                              lazy: i === 0 ? 4 : true,
                             })}
                         </div>
-                    `).join('\n')}
-                `
-            },
+                    `
+                      )
+                      .join('\n')}
+                `,
+      },
 
-            nav: {simple: true}
-        })
-    };
+      nav: {simple: true},
+    }),
+  };
 
-    return [page];
+  return [page];
 }
 
 // Utility functions
 
-function generateNavForFlash(flash, {
-    generateChronologyLinks,
-    generatePreviousNextLinks,
-    link,
-    language,
-    wikiData
-}) {
-    const { flashData, wikiInfo } = wikiData;
-
-    const previousNextLinks = generatePreviousNextLinks(flash, {
-        data: flashData,
-        linkKey: 'flash'
-    });
-
-    return {
-        linkContainerClasses: ['nav-links-hierarchy'],
-        links: [
-            {toHome: true},
-            {
-                path: ['localized.flashIndex'],
-                title: language.$('flashIndex.title')
-            },
-            {
-                html: language.$('flashPage.nav.flash', {
-                    flash: link.flash(flash, {class: 'current'})
-                })
-            },
-        ],
-
-        bottomRowContent: previousNextLinks && `(${previousNextLinks})`,
+function generateNavForFlash(
+  flash,
+  {generateChronologyLinks, generatePreviousNextLinks, link, language, wikiData}
+) {
+  const {flashData} = wikiData;
 
-        content: fixWS`
+  const previousNextLinks = generatePreviousNextLinks(flash, {
+    data: flashData,
+    linkKey: 'flash',
+  });
+
+  return {
+    linkContainerClasses: ['nav-links-hierarchy'],
+    links: [
+      {toHome: true},
+      {
+        path: ['localized.flashIndex'],
+        title: language.$('flashIndex.title'),
+      },
+      {
+        html: language.$('flashPage.nav.flash', {
+          flash: link.flash(flash, {class: 'current'}),
+        }),
+      },
+    ],
+
+    bottomRowContent: previousNextLinks && `(${previousNextLinks})`,
+
+    content: fixWS`
             <div>
                 ${generateChronologyLinks(flash, {
-                    headingString: 'misc.chronology.heading.flash',
-                    contribKey: 'contributorContribs',
-                    getThings: artist => artist.flashesAsContributor
+                  headingString: 'misc.chronology.heading.flash',
+                  contribKey: 'contributorContribs',
+                  getThings: (artist) => artist.flashesAsContributor,
                 })}
             </div>
-        `
-    };
+        `,
+  };
 }
 
 function generateSidebarForFlash(flash, {link, language, wikiData}) {
-    // all hard-coded, sorry :(
-    // this doesnt have a super portable implementation/design...yet!!
-
-    const { flashActData } = wikiData;
-
-    const act6 = flashActData.findIndex(act => act.name.startsWith('Act 6'));
-    const postCanon = flashActData.findIndex(act => act.name.includes('Post Canon'));
-    const outsideCanon = postCanon + flashActData.slice(postCanon).findIndex(act => !act.name.includes('Post Canon'));
-    const actIndex = flashActData.indexOf(flash.act);
-    const side = (
-        (actIndex < 0) ? 0 :
-        (actIndex < act6) ? 1 :
-        (actIndex <= outsideCanon) ? 2 :
-        3
-    );
-    const currentAct = flash && flash.act;
-
-    return {
-        content: fixWS`
-            <h1>${link.flashIndex('', {text: language.$('flashIndex.title')})}</h1>
+  // all hard-coded, sorry :(
+  // this doesnt have a super portable implementation/design...yet!!
+
+  const {flashActData} = wikiData;
+
+  const act6 = flashActData.findIndex((act) => act.name.startsWith('Act 6'));
+  const postCanon = flashActData.findIndex((act) =>
+    act.name.includes('Post Canon')
+  );
+  const outsideCanon =
+    postCanon +
+    flashActData
+      .slice(postCanon)
+      .findIndex((act) => !act.name.includes('Post Canon'));
+  const actIndex = flashActData.indexOf(flash.act);
+  const side =
+    actIndex < 0 ? 0 : actIndex < act6 ? 1 : actIndex <= outsideCanon ? 2 : 3;
+  const currentAct = flash && flash.act;
+
+  return {
+    content: fixWS`
+            <h1>${link.flashIndex('', {
+              text: language.$('flashIndex.title'),
+            })}</h1>
             <dl>
-                ${flashActData.filter(act =>
-                    act.name.startsWith('Act 1') ||
-                    act.name.startsWith('Act 6 Act 1') ||
-                    act.name.startsWith('Hiveswap') ||
-                    // Sorry not sorry -Yiffy
-                    (({index = flashActData.indexOf(act)} = {}) => (
-                        index < act6 ? side === 1 :
-                        index < outsideCanon ? side === 2 :
-                        true
-                    ))()
-                ).flatMap(act => [
-                    act.name.startsWith('Act 1') && html.tag('dt',
+                ${flashActData
+                  .filter(
+                    (act) =>
+                      act.name.startsWith('Act 1') ||
+                      act.name.startsWith('Act 6 Act 1') ||
+                      act.name.startsWith('Hiveswap') ||
+                      // Sorry not sorry -Yiffy
+                      (({index = flashActData.indexOf(act)} = {}) =>
+                        index < act6
+                          ? side === 1
+                          : index < outsideCanon
+                          ? side === 2
+                          : true)()
+                  )
+                  .flatMap((act) => [
+                    (act.name.startsWith('Act 1') &&
+                      html.tag(
+                        'dt',
                         {class: ['side', side === 1 && 'current']},
-                        link.flash(act.flashes[0], {color: '#4ac925', text: `Side 1 (Acts 1-5)`}))
-                    || act.name.startsWith('Act 6 Act 1') && html.tag('dt',
-                        {class: ['side', side === 2 && 'current']},
-                        link.flash(act.flashes[0], {color: '#1076a2', text: `Side 2 (Acts 6-7)`}))
-                    || act.name.startsWith('Hiveswap Act 1') && html.tag('dt',
-                        {class: ['side', side === 3 && 'current']},
-                        link.flash(act.flashes[0], {color: '#008282', text: `Outside Canon (Misc. Games)`})),
-                    (({index = flashActData.indexOf(act)} = {}) => (
-                        index < act6 ? side === 1 :
-                        index < outsideCanon ? side === 2 :
-                        true
-                    ))() && html.tag('dt',
+                        link.flash(act.flashes[0], {
+                          color: '#4ac925',
+                          text: `Side 1 (Acts 1-5)`,
+                        })
+                      )) ||
+                      (act.name.startsWith('Act 6 Act 1') &&
+                        html.tag(
+                          'dt',
+                          {class: ['side', side === 2 && 'current']},
+                          link.flash(act.flashes[0], {
+                            color: '#1076a2',
+                            text: `Side 2 (Acts 6-7)`,
+                          })
+                        )) ||
+                      (act.name.startsWith('Hiveswap Act 1') &&
+                        html.tag(
+                          'dt',
+                          {class: ['side', side === 3 && 'current']},
+                          link.flash(act.flashes[0], {
+                            color: '#008282',
+                            text: `Outside Canon (Misc. Games)`,
+                          })
+                        )),
+                    (({index = flashActData.indexOf(act)} = {}) =>
+                      index < act6
+                        ? side === 1
+                        : index < outsideCanon
+                        ? side === 2
+                        : true)() &&
+                      html.tag(
+                        'dt',
                         {class: act === currentAct && 'current'},
-                        link.flash(act.flashes[0], {text: act.name})),
-                    act === currentAct && fixWS`
+                        link.flash(act.flashes[0], {text: act.name})
+                      ),
+                    act === currentAct &&
+                      fixWS`
                         <dd><ul>
-                            ${act.flashes.map(f => html.tag('li',
-                                {class: f === flash && 'current'},
-                                link.flash(f))).join('\n')}
+                            ${act.flashes
+                              .map((f) =>
+                                html.tag(
+                                  'li',
+                                  {class: f === flash && 'current'},
+                                  link.flash(f)
+                                )
+                              )
+                              .join('\n')}
                         </ul></dd>
-                    `
-                ]).filter(Boolean).join('\n')}
+                    `,
+                  ])
+                  .filter(Boolean)
+                  .join('\n')}
             </dl>
-        `
-    };
+        `,
+  };
 }
diff --git a/src/page/group.js b/src/page/group.js
index b83244a3..5a6b611e 100644
--- a/src/page/group.js
+++ b/src/page/group.js
@@ -1,3 +1,5 @@
+/** @format */
+
 // Group page specifications.
 
 // Imports
@@ -6,264 +8,321 @@ import fixWS from 'fix-whitespace';
 
 import * as html from '../util/html.js';
 
-import {
-    getTotalDuration,
-    sortChronologically,
-} from '../util/wiki-data.js';
+import {getTotalDuration, sortChronologically} from '../util/wiki-data.js';
 
 // Page exports
 
 export function targets({wikiData}) {
-    return wikiData.groupData;
+  return wikiData.groupData;
 }
 
 export function write(group, {wikiData}) {
-    const { listingSpec, wikiInfo } = wikiData;
+  const {listingSpec, wikiInfo} = wikiData;
 
-    const { albums } = group;
-    const tracks = albums.flatMap(album => album.tracks);
-    const totalDuration = getTotalDuration(tracks);
+  const {albums} = group;
+  const tracks = albums.flatMap((album) => album.tracks);
+  const totalDuration = getTotalDuration(tracks);
 
-    const albumLines = group.albums.map(album => ({
-        album,
-        otherGroup: album.groups.find(g => g !== group)
-    }));
+  const albumLines = group.albums.map((album) => ({
+    album,
+    otherGroup: album.groups.find((g) => g !== group),
+  }));
 
-    const infoPage = {
-        type: 'page',
-        path: ['groupInfo', group.directory],
-        page: ({
-            generateInfoGalleryLinks,
-            generatePreviousNextLinks,
-            getLinkThemeString,
-            getThemeString,
-            fancifyURL,
-            link,
-            language,
-            transformMultiline
-        }) => ({
-            title: language.$('groupInfoPage.title', {group: group.name}),
-            theme: getThemeString(group.color),
+  const infoPage = {
+    type: 'page',
+    path: ['groupInfo', group.directory],
+    page: ({
+      generateInfoGalleryLinks,
+      generatePreviousNextLinks,
+      getLinkThemeString,
+      getThemeString,
+      fancifyURL,
+      link,
+      language,
+      transformMultiline,
+    }) => ({
+      title: language.$('groupInfoPage.title', {group: group.name}),
+      theme: getThemeString(group.color),
 
-            main: {
-                content: fixWS`
-                    <h1>${language.$('groupInfoPage.title', {group: group.name})}</h1>
-                    ${group.urls?.length && `<p>${
-                        language.$('releaseInfo.visitOn', {
-                            links: language.formatDisjunctionList(group.urls.map(url => fancifyURL(url, {language})))
-                        })
-                    }</p>`}
+      main: {
+        content: fixWS`
+                    <h1>${language.$('groupInfoPage.title', {
+                      group: group.name,
+                    })}</h1>
+                    ${
+                      group.urls?.length &&
+                      `<p>${language.$('releaseInfo.visitOn', {
+                        links: language.formatDisjunctionList(
+                          group.urls.map((url) => fancifyURL(url, {language}))
+                        ),
+                      })}</p>`
+                    }
                     <blockquote>
                         ${transformMultiline(group.description)}
                     </blockquote>
                     <h2>${language.$('groupInfoPage.albumList.title')}</h2>
-                    <p>${
-                        language.$('groupInfoPage.viewAlbumGallery', {
-                            link: link.groupGallery(group, {
-                                text: language.$('groupInfoPage.viewAlbumGallery.link')
-                            })
-                        })
-                    }</p>
+                    <p>${language.$('groupInfoPage.viewAlbumGallery', {
+                      link: link.groupGallery(group, {
+                        text: language.$('groupInfoPage.viewAlbumGallery.link'),
+                      }),
+                    })}</p>
                     <ul>
-                        ${albumLines.map(({ album, otherGroup }) => {
-                            const item = (album.date
-                                ? language.$('groupInfoPage.albumList.item', {
-                                    year: album.date.getFullYear(),
-                                    album: link.album(album)
+                        ${albumLines
+                          .map(({album, otherGroup}) => {
+                            const item = album.date
+                              ? language.$('groupInfoPage.albumList.item', {
+                                  year: album.date.getFullYear(),
+                                  album: link.album(album),
                                 })
-                                : language.$('groupInfoPage.albumList.item.withoutYear', {
-                                    album: link.album(album)
-                                }));
-                            return html.tag('li', (otherGroup
-                                ? language.$('groupInfoPage.albumList.item.withAccent', {
-                                    item,
-                                    accent: html.tag('span',
+                              : language.$(
+                                  'groupInfoPage.albumList.item.withoutYear',
+                                  {
+                                    album: link.album(album),
+                                  }
+                                );
+                            return html.tag(
+                              'li',
+                              otherGroup
+                                ? language.$(
+                                    'groupInfoPage.albumList.item.withAccent',
+                                    {
+                                      item,
+                                      accent: html.tag(
+                                        'span',
                                         {class: 'other-group-accent'},
-                                        language.$('groupInfoPage.albumList.item.otherGroupAccent', {
-                                            group: link.groupInfo(otherGroup, {color: false})
-                                        }))
-                                })
-                                : item));
-                        }).join('\n')}
+                                        language.$(
+                                          'groupInfoPage.albumList.item.otherGroupAccent',
+                                          {
+                                            group: link.groupInfo(otherGroup, {
+                                              color: false,
+                                            }),
+                                          }
+                                        )
+                                      ),
+                                    }
+                                  )
+                                : item
+                            );
+                          })
+                          .join('\n')}
                     </ul>
-                `
-            },
+                `,
+      },
 
-            sidebarLeft: generateGroupSidebar(group, false, {
-                getLinkThemeString,
-                link,
-                language,
-                wikiData
-            }),
+      sidebarLeft: generateGroupSidebar(group, false, {
+        getLinkThemeString,
+        link,
+        language,
+        wikiData,
+      }),
 
-            nav: generateGroupNav(group, false, {
-                generateInfoGalleryLinks,
-                generatePreviousNextLinks,
-                link,
-                language,
-                wikiData
-            })
-        })
-    };
+      nav: generateGroupNav(group, false, {
+        generateInfoGalleryLinks,
+        generatePreviousNextLinks,
+        link,
+        language,
+        wikiData,
+      }),
+    }),
+  };
 
-    const galleryPage = {
-        type: 'page',
-        path: ['groupGallery', group.directory],
-        page: ({
-            generateInfoGalleryLinks,
-            generatePreviousNextLinks,
-            getAlbumGridHTML,
-            getLinkThemeString,
-            getThemeString,
-            link,
-            language
-        }) => ({
-            title: language.$('groupGalleryPage.title', {group: group.name}),
-            theme: getThemeString(group.color),
+  const galleryPage = {
+    type: 'page',
+    path: ['groupGallery', group.directory],
+    page: ({
+      generateInfoGalleryLinks,
+      generatePreviousNextLinks,
+      getAlbumGridHTML,
+      getLinkThemeString,
+      getThemeString,
+      link,
+      language,
+    }) => ({
+      title: language.$('groupGalleryPage.title', {group: group.name}),
+      theme: getThemeString(group.color),
 
-            main: {
-                classes: ['top-index'],
-                content: fixWS`
-                    <h1>${language.$('groupGalleryPage.title', {group: group.name})}</h1>
-                    <p class="quick-info">${
-                        language.$('groupGalleryPage.infoLine', {
-                            tracks: `<b>${language.countTracks(tracks.length, {unit: true})}</b>`,
-                            albums: `<b>${language.countAlbums(albums.length, {unit: true})}</b>`,
-                            time: `<b>${language.formatDuration(totalDuration, {unit: true})}</b>`
-                        })
-                    }</p>
-                    ${wikiInfo.enableGroupUI && wikiInfo.enableListings && html.tag('p',
+      main: {
+        classes: ['top-index'],
+        content: fixWS`
+                    <h1>${language.$('groupGalleryPage.title', {
+                      group: group.name,
+                    })}</h1>
+                    <p class="quick-info">${language.$(
+                      'groupGalleryPage.infoLine',
+                      {
+                        tracks: `<b>${language.countTracks(tracks.length, {
+                          unit: true,
+                        })}</b>`,
+                        albums: `<b>${language.countAlbums(albums.length, {
+                          unit: true,
+                        })}</b>`,
+                        time: `<b>${language.formatDuration(totalDuration, {
+                          unit: true,
+                        })}</b>`,
+                      }
+                    )}</p>
+                    ${
+                      wikiInfo.enableGroupUI &&
+                      wikiInfo.enableListings &&
+                      html.tag(
+                        'p',
                         {class: 'quick-info'},
                         language.$('groupGalleryPage.anotherGroupLine', {
-                            link: link.listing(listingSpec.find(l => l.directory === 'groups/by-category'), {
-                                text: language.$('groupGalleryPage.anotherGroupLine.link')
-                            })
+                          link: link.listing(
+                            listingSpec.find(
+                              (l) => l.directory === 'groups/by-category'
+                            ),
+                            {
+                              text: language.$(
+                                'groupGalleryPage.anotherGroupLine.link'
+                              ),
+                            }
+                          ),
                         })
-                    )}
+                      )
+                    }
                     <div class="grid-listing">
                         ${getAlbumGridHTML({
-                            entries: sortChronologically(group.albums.map(album => ({
-                                item: album,
-                                directory: album.directory,
-                                name: album.name,
-                                date: album.date,
-                            }))).reverse(),
-                            details: true
+                          entries: sortChronologically(
+                            group.albums.map((album) => ({
+                              item: album,
+                              directory: album.directory,
+                              name: album.name,
+                              date: album.date,
+                            }))
+                          ).reverse(),
+                          details: true,
                         })}
                     </div>
-                `
-            },
+                `,
+      },
 
-            sidebarLeft: generateGroupSidebar(group, true, {
-                getLinkThemeString,
-                link,
-                language,
-                wikiData
-            }),
+      sidebarLeft: generateGroupSidebar(group, true, {
+        getLinkThemeString,
+        link,
+        language,
+        wikiData,
+      }),
 
-            nav: generateGroupNav(group, true, {
-                generateInfoGalleryLinks,
-                generatePreviousNextLinks,
-                link,
-                language,
-                wikiData
-            })
-        })
-    };
+      nav: generateGroupNav(group, true, {
+        generateInfoGalleryLinks,
+        generatePreviousNextLinks,
+        link,
+        language,
+        wikiData,
+      }),
+    }),
+  };
 
-    return [infoPage, galleryPage];
+  return [infoPage, galleryPage];
 }
 
 // Utility functions
 
-function generateGroupSidebar(currentGroup, isGallery, {
-    getLinkThemeString,
-    link,
-    language,
-    wikiData
-}) {
-    const { groupCategoryData, wikiInfo } = wikiData;
+function generateGroupSidebar(
+  currentGroup,
+  isGallery,
+  {getLinkThemeString, link, language, wikiData}
+) {
+  const {groupCategoryData, wikiInfo} = wikiData;
 
-    if (!wikiInfo.enableGroupUI) {
-        return null;
-    }
+  if (!wikiInfo.enableGroupUI) {
+    return null;
+  }
 
-    const linkKey = isGallery ? 'groupGallery' : 'groupInfo';
+  const linkKey = isGallery ? 'groupGallery' : 'groupInfo';
 
-    return {
-        content: fixWS`
+  return {
+    content: fixWS`
             <h1>${language.$('groupSidebar.title')}</h1>
-            ${groupCategoryData.map(category =>
-                html.tag('details', {
+            ${groupCategoryData
+              .map((category) =>
+                html.tag(
+                  'details',
+                  {
                     open: category === currentGroup.category,
-                    class: category === currentGroup.category && 'current'
-                }, [
-                    html.tag('summary',
-                        {style: getLinkThemeString(category.color)},
-                        language.$('groupSidebar.groupList.category', {
-                            category: `<span class="group-name">${category.name}</span>`
-                        })),
-                    html.tag('ul',
-                        category.groups.map(group => html.tag('li',
-                            {
-                                class: group === currentGroup && 'current',
-                                style: getLinkThemeString(group.color)
-                            },
-                            language.$('groupSidebar.groupList.item', {
-                                group: link[linkKey](group)
-                            }))))
-                ])).join('\n')}
+                    class: category === currentGroup.category && 'current',
+                  },
+                  [
+                    html.tag(
+                      'summary',
+                      {style: getLinkThemeString(category.color)},
+                      language.$('groupSidebar.groupList.category', {
+                        category: `<span class="group-name">${category.name}</span>`,
+                      })
+                    ),
+                    html.tag(
+                      'ul',
+                      category.groups.map((group) =>
+                        html.tag(
+                          'li',
+                          {
+                            class: group === currentGroup && 'current',
+                            style: getLinkThemeString(group.color),
+                          },
+                          language.$('groupSidebar.groupList.item', {
+                            group: link[linkKey](group),
+                          })
+                        )
+                      )
+                    ),
+                  ]
+                )
+              )
+              .join('\n')}
             </dl>
-        `
-    };
+        `,
+  };
 }
 
-function generateGroupNav(currentGroup, isGallery, {
+function generateGroupNav(
+  currentGroup,
+  isGallery,
+  {
     generateInfoGalleryLinks,
     generatePreviousNextLinks,
     link,
     language,
-    wikiData
-}) {
-    const { groupData, wikiInfo } = wikiData;
+    wikiData,
+  }
+) {
+  const {groupData, wikiInfo} = wikiData;
 
-    if (!wikiInfo.enableGroupUI) {
-        return {simple: true};
-    }
+  if (!wikiInfo.enableGroupUI) {
+    return {simple: true};
+  }
 
-    const urlKey = isGallery ? 'localized.groupGallery' : 'localized.groupInfo';
-    const linkKey = isGallery ? 'groupGallery' : 'groupInfo';
+  const linkKey = isGallery ? 'groupGallery' : 'groupInfo';
 
-    const infoGalleryLinks = generateInfoGalleryLinks(currentGroup, isGallery, {
-        linkKeyGallery: 'groupGallery',
-        linkKeyInfo: 'groupInfo'
-    });
+  const infoGalleryLinks = generateInfoGalleryLinks(currentGroup, isGallery, {
+    linkKeyGallery: 'groupGallery',
+    linkKeyInfo: 'groupInfo',
+  });
 
-    const previousNextLinks = generatePreviousNextLinks(currentGroup, {
-        data: groupData,
-        linkKey
-    });
+  const previousNextLinks = generatePreviousNextLinks(currentGroup, {
+    data: groupData,
+    linkKey,
+  });
 
-    return {
-        linkContainerClasses: ['nav-links-hierarchy'],
-        links: [
-            {toHome: true},
-            wikiInfo.enableListings &&
-            {
-                path: ['localized.listingIndex'],
-                title: language.$('listingIndex.title')
-            },
-            {
-                html: language.$('groupPage.nav.group', {
-                    group: link[linkKey](currentGroup, {class: 'current'})
-                })
-            },
-            {
-                divider: false,
-                html: (previousNextLinks
-                    ? `(${infoGalleryLinks}; ${previousNextLinks})`
-                    : `(${previousNextLinks})`)
-            }
-        ]
-    };
+  return {
+    linkContainerClasses: ['nav-links-hierarchy'],
+    links: [
+      {toHome: true},
+      wikiInfo.enableListings && {
+        path: ['localized.listingIndex'],
+        title: language.$('listingIndex.title'),
+      },
+      {
+        html: language.$('groupPage.nav.group', {
+          group: link[linkKey](currentGroup, {class: 'current'}),
+        }),
+      },
+      {
+        divider: false,
+        html: previousNextLinks
+          ? `(${infoGalleryLinks}; ${previousNextLinks})`
+          : `(${previousNextLinks})`,
+      },
+    ],
+  };
 }
diff --git a/src/page/homepage.js b/src/page/homepage.js
index a19df6cf..1356aaf5 100644
--- a/src/page/homepage.js
+++ b/src/page/homepage.js
@@ -1,3 +1,5 @@
+/** @format */
+
 // Homepage specification.
 
 // Imports
@@ -6,119 +8,184 @@ import fixWS from 'fix-whitespace';
 
 import * as html from '../util/html.js';
 
-import {
-    getNewAdditions,
-    getNewReleases
-} from '../util/wiki-data.js';
+import {getNewAdditions, getNewReleases} from '../util/wiki-data.js';
 
 // Page exports
 
 export function writeTargetless({wikiData}) {
-    const { newsData, staticPageData, homepageLayout, wikiInfo } = wikiData;
-
-    const page = {
-        type: 'page',
-        path: ['home'],
-        page: ({
-            getAlbumGridHTML,
-            getLinkThemeString,
-            link,
-            language,
-            to,
-            transformInline,
-            transformMultiline
-        }) => ({
-            title: wikiInfo.name,
-            showWikiNameInTitle: false,
-
-            meta: {
-                description: wikiInfo.description
-            },
-
-            main: {
-                classes: ['top-index'],
-                content: fixWS`
+  const {newsData, staticPageData, homepageLayout, wikiInfo} = wikiData;
+
+  const page = {
+    type: 'page',
+    path: ['home'],
+    page: ({
+      getAlbumGridHTML,
+      getLinkThemeString,
+      link,
+      language,
+      to,
+      transformInline,
+      transformMultiline,
+    }) => ({
+      title: wikiInfo.name,
+      showWikiNameInTitle: false,
+
+      meta: {
+        description: wikiInfo.description,
+      },
+
+      main: {
+        classes: ['top-index'],
+        content: fixWS`
                     <h1>${wikiInfo.name}</h1>
-                    ${homepageLayout.rows?.map((row, i) => fixWS`
-                        <section class="row" style="${getLinkThemeString(row.color)}">
+                    ${homepageLayout.rows
+                      ?.map(
+                        (row, i) => fixWS`
+                        <section class="row" style="${getLinkThemeString(
+                          row.color
+                        )}">
                             <h2>${row.name}</h2>
-                            ${row.type === 'albums' && fixWS`
+                            ${
+                              row.type === 'albums' &&
+                              fixWS`
                                 <div class="grid-listing">
                                     ${getAlbumGridHTML({
-                                        entries: (
-                                            row.sourceGroupByRef === 'new-releases' ? getNewReleases(row.countAlbumsFromGroup, {wikiData}) :
-                                            row.sourceGroupByRef === 'new-additions' ? getNewAdditions(row.countAlbumsFromGroup, {wikiData}) :
-                                            ((row.sourceGroup?.albums ?? [])
-                                                .slice()
-                                                .reverse()
-                                                .filter(album => album.isListedOnHomepage)
-                                                .slice(0, row.countAlbumsFromGroup)
-                                                .map(album => ({item: album})))
-                                        ).concat(row.sourceAlbums.map(album => ({item: album}))),
-                                        lazy: i > 0
+                                      entries: (row.sourceGroupByRef ===
+                                      'new-releases'
+                                        ? getNewReleases(
+                                            row.countAlbumsFromGroup,
+                                            {
+                                              wikiData,
+                                            }
+                                          )
+                                        : row.sourceGroupByRef ===
+                                          'new-additions'
+                                        ? getNewAdditions(
+                                            row.countAlbumsFromGroup,
+                                            {
+                                              wikiData,
+                                            }
+                                          )
+                                        : (row.sourceGroup?.albums ?? [])
+                                            .slice()
+                                            .reverse()
+                                            .filter(
+                                              (album) =>
+                                                album.isListedOnHomepage
+                                            )
+                                            .slice(0, row.countAlbumsFromGroup)
+                                            .map((album) => ({item: album}))
+                                      ).concat(
+                                        row.sourceAlbums.map((album) => ({
+                                          item: album,
+                                        }))
+                                      ),
+                                      lazy: i > 0,
                                     })}
-                                    ${row.actionLinks?.length && fixWS`
+                                    ${
+                                      row.actionLinks?.length &&
+                                      fixWS`
                                         <div class="grid-actions">
-                                            ${row.actionLinks.map(action => transformInline(action)
-                                                .replace('<a', '<a class="box grid-item"')).join('\n')}
+                                            ${row.actionLinks
+                                              .map((action) =>
+                                                transformInline(action).replace(
+                                                  '<a',
+                                                  '<a class="box grid-item"'
+                                                )
+                                              )
+                                              .join('\n')}
                                         </div>
-                                    `}
+                                    `
+                                    }
                                 </div>
-                            `}
+                            `
+                            }
                         </section>
-                    `).join('\n')}
-                `
-            },
-
-            sidebarLeft: homepageLayout.sidebarContent && {
-                wide: true,
-                collapse: false,
-                // This is a pretty filthy hack! 8ut otherwise, the [[news]] part
-                // gets treated like it's a reference to the track named "news",
-                // which o8viously isn't what we're going for. Gotta catch that
-                // 8efore we pass it to transformMultiline, 'cuz otherwise it'll
-                // get repl8ced with just the word "news" (or anything else that
-                // transformMultiline does with references it can't match) -- and
-                // we can't match that for replacing it with the news column!
-                //
-                // And no, I will not make [[news]] into part of transformMultiline
-                // (even though that would 8e hilarious).
-                content: (transformMultiline(homepageLayout.sidebarContent.replace('[[news]]', '__GENERATE_NEWS__'))
-                    .replace('<p>__GENERATE_NEWS__</p>', wikiInfo.enableNews ? fixWS`
+                    `
+                      )
+                      .join('\n')}
+                `,
+      },
+
+      sidebarLeft: homepageLayout.sidebarContent && {
+        wide: true,
+        collapse: false,
+        // This is a pretty filthy hack! 8ut otherwise, the [[news]] part
+        // gets treated like it's a reference to the track named "news",
+        // which o8viously isn't what we're going for. Gotta catch that
+        // 8efore we pass it to transformMultiline, 'cuz otherwise it'll
+        // get repl8ced with just the word "news" (or anything else that
+        // transformMultiline does with references it can't match) -- and
+        // we can't match that for replacing it with the news column!
+        //
+        // And no, I will not make [[news]] into part of transformMultiline
+        // (even though that would 8e hilarious).
+        content: transformMultiline(
+          homepageLayout.sidebarContent.replace('[[news]]', '__GENERATE_NEWS__')
+        ).replace(
+          '<p>__GENERATE_NEWS__</p>',
+          wikiInfo.enableNews
+            ? fixWS`
                         <h1>${language.$('homepage.news.title')}</h1>
-                        ${newsData.slice(0, 3).map((entry, i) => html.tag('article',
-                            {class: ['news-entry', i === 0 && 'first-news-entry']},
-                            fixWS`
-                                <h2><time>${language.formatDate(entry.date)}</time> ${link.newsEntry(entry)}</h2>
+                        ${newsData
+                          .slice(0, 3)
+                          .map((entry, i) =>
+                            html.tag(
+                              'article',
+                              {
+                                class: [
+                                  'news-entry',
+                                  i === 0 && 'first-news-entry',
+                                ],
+                              },
+                              fixWS`
+                                <h2><time>${language.formatDate(
+                                  entry.date
+                                )}</time> ${link.newsEntry(entry)}</h2>
                                 ${transformMultiline(entry.contentShort)}
-                                ${entry.contentShort !== entry.content && link.newsEntry(entry, {
-                                    text: language.$('homepage.news.entry.viewRest')
-                                })}
-                            `)).join('\n')}
-                    ` : `<p><i>News requested in content description but this feature isn't enabled</i></p>`))
-            },
-
-            nav: {
-                linkContainerClasses: ['nav-links-index'],
-                links: [
-                    link.home('', {text: wikiInfo.nameShort, class: 'current', to}),
-
-                    wikiInfo.enableListings &&
-                    link.listingIndex('', {text: language.$('listingIndex.title'), to}),
-
-                    wikiInfo.enableNews &&
-                    link.newsIndex('', {text: language.$('newsIndex.title'), to}),
-
-                    wikiInfo.enableFlashesAndGames &&
-                    link.flashIndex('', {text: language.$('flashIndex.title'), to}),
-
-                    ...(staticPageData
-                        .filter(page => page.showInNavigationBar)
-                        .map(page => link.staticPage(page, {text: page.nameShort}))),
-                ].filter(Boolean).map(html => ({html})),
-            }
-        })
-    };
-
-    return [page];
+                                ${
+                                  entry.contentShort !== entry.content &&
+                                  link.newsEntry(entry, {
+                                    text: language.$(
+                                      'homepage.news.entry.viewRest'
+                                    ),
+                                  })
+                                }
+                            `
+                            )
+                          )
+                          .join('\n')}
+                    `
+            : `<p><i>News requested in content description but this feature isn't enabled</i></p>`
+        ),
+      },
+
+      nav: {
+        linkContainerClasses: ['nav-links-index'],
+        links: [
+          link.home('', {text: wikiInfo.nameShort, class: 'current', to}),
+
+          wikiInfo.enableListings &&
+            link.listingIndex('', {
+              text: language.$('listingIndex.title'),
+              to,
+            }),
+
+          wikiInfo.enableNews &&
+            link.newsIndex('', {text: language.$('newsIndex.title'), to}),
+
+          wikiInfo.enableFlashesAndGames &&
+            link.flashIndex('', {text: language.$('flashIndex.title'), to}),
+
+          ...staticPageData
+            .filter((page) => page.showInNavigationBar)
+            .map((page) => link.staticPage(page, {text: page.nameShort})),
+        ]
+          .filter(Boolean)
+          .map((html) => ({html})),
+      },
+    }),
+  };
+
+  return [page];
 }
diff --git a/src/page/index.js b/src/page/index.js
index f580cbea..149503f0 100644
--- a/src/page/index.js
+++ b/src/page/index.js
@@ -1,3 +1,5 @@
+/** @format */
+
 // 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.
diff --git a/src/page/listing.js b/src/page/listing.js
index 447a0c8f..5db6c916 100644
--- a/src/page/listing.js
+++ b/src/page/listing.js
@@ -1,3 +1,5 @@
+/** @format */
+
 // Listing page specification.
 //
 // The targets here are a bit different than for most pages: rather than data
@@ -14,189 +16,212 @@ import fixWS from 'fix-whitespace';
 
 import * as html from '../util/html.js';
 
-import {
-    getTotalDuration
-} from '../util/wiki-data.js';
+import {getTotalDuration} from '../util/wiki-data.js';
 
 // Page exports
 
 export function condition({wikiData}) {
-    return wikiData.wikiInfo.enableListings;
+  return wikiData.wikiInfo.enableListings;
 }
 
 export function targets({wikiData}) {
-    return wikiData.listingSpec;
+  return wikiData.listingSpec;
 }
 
 export function write(listing, {wikiData}) {
-    if (listing.condition && !listing.condition({wikiData})) {
-        return null;
-    }
-
-    const { wikiInfo } = wikiData;
+  if (listing.condition && !listing.condition({wikiData})) {
+    return null;
+  }
 
-    const data = (listing.data
-        ? listing.data({wikiData})
-        : null);
+  const data = listing.data ? listing.data({wikiData}) : null;
 
-    const page = {
-        type: 'page',
-        path: ['listing', listing.directory],
-        page: opts => {
-            const { getLinkThemeString, link, language } = opts;
-            const titleKey = `listingPage.${listing.stringsKey}.title`;
+  const page = {
+    type: 'page',
+    path: ['listing', listing.directory],
+    page: (opts) => {
+      const {getLinkThemeString, link, language} = opts;
+      const titleKey = `listingPage.${listing.stringsKey}.title`;
 
-            return {
-                title: language.$(titleKey),
+      return {
+        title: language.$(titleKey),
 
-                main: {
-                    content: fixWS`
+        main: {
+          content: fixWS`
                         <h1>${language.$(titleKey)}</h1>
-                        ${listing.html && (listing.data
+                        ${
+                          listing.html &&
+                          (listing.data
                             ? listing.html(data, opts)
-                            : listing.html(opts))}
-                        ${listing.row && fixWS`
+                            : listing.html(opts))
+                        }
+                        ${
+                          listing.row &&
+                          fixWS`
                             <ul>
-                                ${(data
-                                    .map(item => listing.row(item, opts))
-                                    .map(row => `<li>${row}</li>`)
-                                    .join('\n'))}
+                                ${data
+                                  .map((item) => listing.row(item, opts))
+                                  .map((row) => `<li>${row}</li>`)
+                                  .join('\n')}
                             </ul>
-                        `}
-                    `
-                },
-
-                sidebarLeft: {
-                    content: generateSidebarForListings(listing, {
-                        getLinkThemeString,
-                        link,
-                        language,
-                        wikiData
-                    })
-                },
-
-                nav: {
-                    linkContainerClasses: ['nav-links-hierarchy'],
-                    links: [
-                        {toHome: true},
-                        {
-                            path: ['localized.listingIndex'],
-                            title: language.$('listingIndex.title')
-                        },
-                        {toCurrentPage: true}
-                    ]
-                }
-            };
-        }
-    };
-
-    return [page];
+                        `
+                        }
+                    `,
+        },
+
+        sidebarLeft: {
+          content: generateSidebarForListings(listing, {
+            getLinkThemeString,
+            link,
+            language,
+            wikiData,
+          }),
+        },
+
+        nav: {
+          linkContainerClasses: ['nav-links-hierarchy'],
+          links: [
+            {toHome: true},
+            {
+              path: ['localized.listingIndex'],
+              title: language.$('listingIndex.title'),
+            },
+            {toCurrentPage: true},
+          ],
+        },
+      };
+    },
+  };
+
+  return [page];
 }
 
 export function writeTargetless({wikiData}) {
-    const { albumData, trackData, wikiInfo } = wikiData;
+  const {albumData, trackData, wikiInfo} = wikiData;
 
-    const totalDuration = getTotalDuration(trackData);
+  const totalDuration = getTotalDuration(trackData);
 
-    const page = {
-        type: 'page',
-        path: ['listingIndex'],
-        page: ({
-            getLinkThemeString,
-            language,
-            link
-        }) => ({
-            title: language.$('listingIndex.title'),
+  const page = {
+    type: 'page',
+    path: ['listingIndex'],
+    page: ({getLinkThemeString, language, link}) => ({
+      title: language.$('listingIndex.title'),
 
-            main: {
-                content: fixWS`
+      main: {
+        content: fixWS`
                     <h1>${language.$('listingIndex.title')}</h1>
                     <p>${language.$('listingIndex.infoLine', {
-                        wiki: wikiInfo.name,
-                        tracks: `<b>${language.countTracks(trackData.length, {unit: true})}</b>`,
-                        albums: `<b>${language.countAlbums(albumData.length, {unit: true})}</b>`,
-                        duration: `<b>${language.formatDuration(totalDuration, {approximate: true, unit: true})}</b>`
+                      wiki: wikiInfo.name,
+                      tracks: `<b>${language.countTracks(trackData.length, {
+                        unit: true,
+                      })}</b>`,
+                      albums: `<b>${language.countAlbums(albumData.length, {
+                        unit: true,
+                      })}</b>`,
+                      duration: `<b>${language.formatDuration(totalDuration, {
+                        approximate: true,
+                        unit: true,
+                      })}</b>`,
                     })}</p>
                     <hr>
                     <p>${language.$('listingIndex.exploreList')}</p>
-                    ${generateLinkIndexForListings(null, false, {link, language, wikiData})}
-                `
-            },
-
-            sidebarLeft: {
-                content: generateSidebarForListings(null, {
-                    getLinkThemeString,
-                    link,
-                    language,
-                    wikiData
-                })
-            },
-
-            nav: {simple: true}
-        })
-    };
-
-    return [page];
-};
+                    ${generateLinkIndexForListings(null, false, {
+                      link,
+                      language,
+                      wikiData,
+                    })}
+                `,
+      },
+
+      sidebarLeft: {
+        content: generateSidebarForListings(null, {
+          getLinkThemeString,
+          link,
+          language,
+          wikiData,
+        }),
+      },
+
+      nav: {simple: true},
+    }),
+  };
+
+  return [page];
+}
 
 // Utility functions
 
-function generateSidebarForListings(currentListing, {
-    getLinkThemeString,
-    link,
-    language,
-    wikiData
-}) {
-    return fixWS`
-        <h1>${link.listingIndex('', {text: language.$('listingIndex.title')})}</h1>
+function generateSidebarForListings(
+  currentListing,
+  {getLinkThemeString, link, language, wikiData}
+) {
+  return fixWS`
+        <h1>${link.listingIndex('', {
+          text: language.$('listingIndex.title'),
+        })}</h1>
         ${generateLinkIndexForListings(currentListing, true, {
-            getLinkThemeString,
-            link,
-            language,
-            wikiData
+          getLinkThemeString,
+          link,
+          language,
+          wikiData,
         })}
     `;
 }
 
-function generateLinkIndexForListings(currentListing, forSidebar, {
-    getLinkThemeString,
-    link,
-    language,
-    wikiData
-}) {
-    const { listingTargetSpec, wikiInfo } = wikiData;
-
-    const filteredByCondition = listingTargetSpec
-        .map(({ listings, ...rest }) => ({
-            ...rest,
-            listings: listings.filter(({ condition: c }) => !c || c({wikiData}))
-        }))
-        .filter(({ listings }) => listings.length > 0);
-
-    const genUL = listings => html.tag('ul',
-        listings.map(listing => html.tag('li',
-            {class: [listing === currentListing && 'current']},
-            link.listing(listing, {text: language.$(`listingPage.${listing.stringsKey}.title.short`)})
-        )));
-
-    if (forSidebar) {
-        return filteredByCondition.map(({ title, listings }) =>
-            html.tag('details', {
-                open: !forSidebar || listings.includes(currentListing),
-                class: listings.includes(currentListing) && 'current'
-            }, [
-                html.tag('summary',
-                    {style: getLinkThemeString(wikiInfo.color)},
-                    html.tag('span',
-                        {class: 'group-name'},
-                        title({language}))),
-                genUL(listings)
-            ])).join('\n');
-    } else {
-        return html.tag('dl',
-            filteredByCondition.flatMap(({ title, listings }) => [
-                html.tag('dt', title({language})),
-                html.tag('dd', genUL(listings))
-            ]));
-    }
+function generateLinkIndexForListings(
+  currentListing,
+  forSidebar,
+  {getLinkThemeString, link, language, wikiData}
+) {
+  const {listingTargetSpec, wikiInfo} = wikiData;
+
+  const filteredByCondition = listingTargetSpec
+    .map(({listings, ...rest}) => ({
+      ...rest,
+      listings: listings.filter(({condition: c}) => !c || c({wikiData})),
+    }))
+    .filter(({listings}) => listings.length > 0);
+
+  const genUL = (listings) =>
+    html.tag(
+      'ul',
+      listings.map((listing) =>
+        html.tag(
+          'li',
+          {class: [listing === currentListing && 'current']},
+          link.listing(listing, {
+            text: language.$(`listingPage.${listing.stringsKey}.title.short`),
+          })
+        )
+      )
+    );
+
+  if (forSidebar) {
+    return filteredByCondition
+      .map(({title, listings}) =>
+        html.tag(
+          'details',
+          {
+            open: !forSidebar || listings.includes(currentListing),
+            class: listings.includes(currentListing) && 'current',
+          },
+          [
+            html.tag(
+              'summary',
+              {style: getLinkThemeString(wikiInfo.color)},
+              html.tag('span', {class: 'group-name'}, title({language}))
+            ),
+            genUL(listings),
+          ]
+        )
+      )
+      .join('\n');
+  } else {
+    return html.tag(
+      'dl',
+      filteredByCondition.flatMap(({title, listings}) => [
+        html.tag('dt', title({language})),
+        html.tag('dd', genUL(listings)),
+      ])
+    );
+  }
 }
diff --git a/src/page/news.js b/src/page/news.js
index 9336506f..478ff9d0 100644
--- a/src/page/news.js
+++ b/src/page/news.js
@@ -1,3 +1,5 @@
+/** @format */
+
 // News entry & index page specifications.
 
 // Imports
@@ -7,121 +9,130 @@ import fixWS from 'fix-whitespace';
 // Page exports
 
 export function condition({wikiData}) {
-    return wikiData.wikiInfo.enableNews;
+  return wikiData.wikiInfo.enableNews;
 }
 
 export function targets({wikiData}) {
-    return wikiData.newsData;
+  return wikiData.newsData;
 }
 
 export function write(entry, {wikiData}) {
-    const page = {
-        type: 'page',
-        path: ['newsEntry', entry.directory],
-        page: ({
-            generatePreviousNextLinks,
-            link,
-            language,
-            transformMultiline,
-        }) => ({
-            title: language.$('newsEntryPage.title', {entry: entry.name}),
-
-            main: {
-                content: fixWS`
+  const page = {
+    type: 'page',
+    path: ['newsEntry', entry.directory],
+    page: ({
+      generatePreviousNextLinks,
+      link,
+      language,
+      transformMultiline,
+    }) => ({
+      title: language.$('newsEntryPage.title', {entry: entry.name}),
+
+      main: {
+        content: fixWS`
                     <div class="long-content">
-                        <h1>${language.$('newsEntryPage.title', {entry: entry.name})}</h1>
-                        <p>${language.$('newsEntryPage.published', {date: language.formatDate(entry.date)})}</p>
+                        <h1>${language.$('newsEntryPage.title', {
+                          entry: entry.name,
+                        })}</h1>
+                        <p>${language.$('newsEntryPage.published', {
+                          date: language.formatDate(entry.date),
+                        })}</p>
                         ${transformMultiline(entry.content)}
                     </div>
-                `
-            },
-
-            nav: generateNewsEntryNav(entry, {
-                generatePreviousNextLinks,
-                link,
-                language,
-                wikiData
-            })
-        })
-    };
-
-    return [page];
+                `,
+      },
+
+      nav: generateNewsEntryNav(entry, {
+        generatePreviousNextLinks,
+        link,
+        language,
+        wikiData,
+      }),
+    }),
+  };
+
+  return [page];
 }
 
 export function writeTargetless({wikiData}) {
-    const { newsData } = wikiData;
-
-    const page = {
-        type: 'page',
-        path: ['newsIndex'],
-        page: ({
-            link,
-            language,
-            transformMultiline
-        }) => ({
-            title: language.$('newsIndex.title'),
-
-            main: {
-                content: fixWS`
+  const {newsData} = wikiData;
+
+  const page = {
+    type: 'page',
+    path: ['newsIndex'],
+    page: ({link, language, transformMultiline}) => ({
+      title: language.$('newsIndex.title'),
+
+      main: {
+        content: fixWS`
                     <div class="long-content news-index">
                         <h1>${language.$('newsIndex.title')}</h1>
-                        ${newsData.map(entry => fixWS`
+                        ${newsData
+                          .map(
+                            (entry) => fixWS`
                             <article id="${entry.directory}">
-                                <h2><time>${language.formatDate(entry.date)}</time> ${link.newsEntry(entry)}</h2>
+                                <h2><time>${language.formatDate(
+                                  entry.date
+                                )}</time> ${link.newsEntry(entry)}</h2>
                                 ${transformMultiline(entry.contentShort)}
-                                ${entry.contentShort !== entry.content && `<p>${link.newsEntry(entry, {
-                                    text: language.$('newsIndex.entry.viewRest')
-                                })}</p>`}
+                                ${
+                                  entry.contentShort !== entry.content &&
+                                  `<p>${link.newsEntry(entry, {
+                                    text: language.$(
+                                      'newsIndex.entry.viewRest'
+                                    ),
+                                  })}</p>`
+                                }
                             </article>
-                        `).join('\n')}
+                        `
+                          )
+                          .join('\n')}
                     </div>
-                `
-            },
+                `,
+      },
 
-            nav: {simple: true}
-        })
-    };
+      nav: {simple: true},
+    }),
+  };
 
-    return [page];
+  return [page];
 }
 
 // Utility functions
 
-function generateNewsEntryNav(entry, {
-    generatePreviousNextLinks,
+function generateNewsEntryNav(
+  entry,
+  {generatePreviousNextLinks, link, language, wikiData}
+) {
+  const {newsData} = wikiData;
+
+  // The newsData list is sorted reverse chronologically (newest ones first),
+  // so the way we find next/previous entries is flipped from normal.
+  const previousNextLinks = generatePreviousNextLinks(entry, {
     link,
     language,
-    wikiData
-}) {
-    const { wikiInfo, newsData } = wikiData;
-
-    // The newsData list is sorted reverse chronologically (newest ones first),
-    // so the way we find next/previous entries is flipped from normal.
-    const previousNextLinks = generatePreviousNextLinks(entry, {
-        link, language,
-        data: newsData.slice().reverse(),
-        linkKey: 'newsEntry'
-    });
-
-    return {
-        linkContainerClasses: ['nav-links-hierarchy'],
-        links: [
-            {toHome: true},
-            {
-                path: ['localized.newsIndex'],
-                title: language.$('newsEntryPage.nav.news')
-            },
-            {
-                html: language.$('newsEntryPage.nav.entry', {
-                    date: language.formatDate(entry.date),
-                    entry: link.newsEntry(entry, {class: 'current'})
-                })
-            },
-            previousNextLinks &&
-            {
-                divider: false,
-                html: `(${previousNextLinks})`
-            }
-        ]
-    };
+    data: newsData.slice().reverse(),
+    linkKey: 'newsEntry',
+  });
+
+  return {
+    linkContainerClasses: ['nav-links-hierarchy'],
+    links: [
+      {toHome: true},
+      {
+        path: ['localized.newsIndex'],
+        title: language.$('newsEntryPage.nav.news'),
+      },
+      {
+        html: language.$('newsEntryPage.nav.entry', {
+          date: language.formatDate(entry.date),
+          entry: link.newsEntry(entry, {class: 'current'}),
+        }),
+      },
+      previousNextLinks && {
+        divider: false,
+        html: `(${previousNextLinks})`,
+      },
+    ],
+  };
 }
diff --git a/src/page/static.js b/src/page/static.js
index e9b6a047..2a49ff87 100644
--- a/src/page/static.js
+++ b/src/page/static.js
@@ -1,3 +1,5 @@
+/** @format */
+
 // Static content page specification. (These are static pages coded into the
 // wiki data folder, used for a variety of purposes, e.g. wiki info,
 // changelog, and so on.)
@@ -9,32 +11,29 @@ import fixWS from 'fix-whitespace';
 // Page exports
 
 export function targets({wikiData}) {
-    return wikiData.staticPageData;
+  return wikiData.staticPageData;
 }
 
-export function write(staticPage, {wikiData}) {
-    const page = {
-        type: 'page',
-        path: ['staticPage', staticPage.directory],
-        page: ({
-            language,
-            transformMultiline
-        }) => ({
-            title: staticPage.name,
-            stylesheet: staticPage.stylesheet,
-
-            main: {
-                content: fixWS`
+export function write(staticPage) {
+  const page = {
+    type: 'page',
+    path: ['staticPage', staticPage.directory],
+    page: ({transformMultiline}) => ({
+      title: staticPage.name,
+      stylesheet: staticPage.stylesheet,
+
+      main: {
+        content: fixWS`
                     <div class="long-content">
                         <h1>${staticPage.name}</h1>
                         ${transformMultiline(staticPage.content)}
                     </div>
-                `
-            },
+                `,
+      },
 
-            nav: {simple: true}
-        })
-    };
+      nav: {simple: true},
+    }),
+  };
 
-    return [page];
+  return [page];
 }
diff --git a/src/page/tag.js b/src/page/tag.js
index 471439da..38f7e213 100644
--- a/src/page/tag.js
+++ b/src/page/tag.js
@@ -1,3 +1,5 @@
+/** @format */
+
 // Art tag page specification.
 
 // Imports
@@ -7,105 +9,91 @@ import fixWS from 'fix-whitespace';
 // Page exports
 
 export function condition({wikiData}) {
-    return wikiData.wikiInfo.enableArtTagUI;
+  return wikiData.wikiInfo.enableArtTagUI;
 }
 
 export function targets({wikiData}) {
-    return wikiData.artTagData.filter(tag => !tag.isContentWarning);
+  return wikiData.artTagData.filter((tag) => !tag.isContentWarning);
 }
 
 export function write(tag, {wikiData}) {
-    const { wikiInfo } = wikiData;
-    const { taggedInThings: things } = tag;
+  const {taggedInThings: things} = tag;
 
-    // Display things featuring this art tag in reverse chronological order,
-    // sticking the most recent additions near the top!
-    const thingsReversed = things.slice().reverse();
+  // Display things featuring this art tag in reverse chronological order,
+  // sticking the most recent additions near the top!
+  const thingsReversed = things.slice().reverse();
 
-    const entries = thingsReversed.map(item => ({item}));
+  const entries = thingsReversed.map((item) => ({item}));
 
-    const page = {
-        type: 'page',
-        path: ['tag', tag.directory],
-        page: ({
-            generatePreviousNextLinks,
-            getAlbumCover,
-            getGridHTML,
-            getThemeString,
-            getTrackCover,
-            link,
-            language,
-            to
-        }) => ({
-            title: language.$('tagPage.title', {tag: tag.name}),
-            theme: getThemeString(tag.color),
+  const page = {
+    type: 'page',
+    path: ['tag', tag.directory],
+    page: ({
+      getAlbumCover,
+      getGridHTML,
+      getThemeString,
+      getTrackCover,
+      link,
+      language,
+    }) => ({
+      title: language.$('tagPage.title', {tag: tag.name}),
+      theme: getThemeString(tag.color),
 
-            main: {
-                classes: ['top-index'],
-                content: fixWS`
+      main: {
+        classes: ['top-index'],
+        content: fixWS`
                     <h1>${language.$('tagPage.title', {tag: tag.name})}</h1>
                     <p class="quick-info">${language.$('tagPage.infoLine', {
-                        coverArts: language.countCoverArts(things.length, {unit: true})
+                      coverArts: language.countCoverArts(things.length, {
+                        unit: true,
+                      }),
                     })}</p>
                     <div class="grid-listing">
                         ${getGridHTML({
-                            entries,
-                            srcFn: thing => (thing.album
-                                ? getTrackCover(thing)
-                                : getAlbumCover(thing)),
-                            linkFn: (thing, opts) => (thing.album
-                                ? link.track(thing, opts)
-                                : link.album(thing, opts))
+                          entries,
+                          srcFn: (thing) =>
+                            thing.album
+                              ? getTrackCover(thing)
+                              : getAlbumCover(thing),
+                          linkFn: (thing, opts) =>
+                            thing.album
+                              ? link.track(thing, opts)
+                              : link.album(thing, opts),
                         })}
                     </div>
-                `
-            },
+                `,
+      },
 
-            nav: generateTagNav(tag, {
-                generatePreviousNextLinks,
-                link,
-                language,
-                wikiData
-            })
-        })
-    };
+      nav: generateTagNav(tag, {
+        link,
+        language,
+        wikiData,
+      }),
+    }),
+  };
 
-    return [page];
+  return [page];
 }
 
 // Utility functions
 
-function generateTagNav(tag, {
-    generatePreviousNextLinks,
-    link,
-    language,
-    wikiData
-}) {
-    const previousNextLinks = generatePreviousNextLinks(tag, {
-        data: wikiData.artTagData.filter(tag => !tag.isContentWarning),
-        linkKey: 'tag'
-    });
-
-    return {
-        linkContainerClasses: ['nav-links-hierarchy'],
-        links: [
-            {toHome: true},
-            wikiData.wikiInfo.enableListings &&
-            {
-                path: ['localized.listingIndex'],
-                title: language.$('listingIndex.title')
-            },
-            {
-                html: language.$('tagPage.nav.tag', {
-                    tag: link.tag(tag, {class: 'current'})
-                })
-            },
-            /*
-            previousNextLinks && {
-                divider: false,
-                html: `(${previousNextLinks})`
-            }
-            */
-        ]
-    };
+function generateTagNav(
+  tag,
+  {link, language, wikiData}
+) {
+  return {
+    linkContainerClasses: ['nav-links-hierarchy'],
+    links: [
+      {toHome: true},
+      wikiData.wikiInfo.enableListings && {
+        path: ['localized.listingIndex'],
+        title: language.$('listingIndex.title'),
+      },
+      {
+        html: language.$('tagPage.nav.tag', {
+          tag: link.tag(tag, {class: 'current'}),
+        }),
+      },
+    ],
+  };
 }
diff --git a/src/page/track.js b/src/page/track.js
index c4ec6c59..29a07431 100644
--- a/src/page/track.js
+++ b/src/page/track.js
@@ -1,3 +1,5 @@
+/** @format */
+
 // Track page specification.
 
 // Imports
@@ -5,183 +7,205 @@
 import fixWS from 'fix-whitespace';
 
 import {
-    generateAlbumChronologyLinks,
-    generateAlbumNavLinks,
-    generateAlbumSecondaryNav,
-    generateAlbumSidebar
+  generateAlbumChronologyLinks,
+  generateAlbumNavLinks,
+  generateAlbumSecondaryNav,
+  generateAlbumSidebar,
 } from './album.js';
 
 import * as html from '../util/html.js';
 
-import {
-    bindOpts
-} from '../util/sugar.js';
+import {bindOpts} from '../util/sugar.js';
 
 import {
-    getTrackCover,
-    getAlbumListTag,
-    sortChronologically,
+  getTrackCover,
+  getAlbumListTag,
+  sortChronologically,
 } from '../util/wiki-data.js';
 
 // Page exports
 
 export function targets({wikiData}) {
-    return wikiData.trackData;
+  return wikiData.trackData;
 }
 
 export function write(track, {wikiData}) {
-    const { groupData, wikiInfo } = wikiData;
-    const { album, referencedByTracks, referencedTracks, otherReleases } = track;
-
-    const listTag = getAlbumListTag(album);
+  const {wikiInfo} = wikiData;
+  const {album, referencedByTracks, referencedTracks, otherReleases} = track;
 
-    let flashesThatFeature;
-    if (wikiInfo.enableFlashesAndGames) {
-        flashesThatFeature = sortChronologically([track, ...otherReleases]
-            .flatMap(track => track.featuredInFlashes
-                .map(flash => ({
-                    flash,
-                    as: track,
-                    directory: flash.directory,
-                    name: flash.name,
-                    date: flash.date
-                }))));
-    }
+  const listTag = getAlbumListTag(album);
 
-    const unbound_getTrackItem = (track, {getArtistString, link, language}) => (
-        html.tag('li', language.$('trackList.item.withArtists', {
-            track: link.track(track),
-            by: `<span class="by">${language.$('trackList.item.withArtists.by', {
-                artists: getArtistString(track.artistContribs)
-            })}</span>`
-        })));
+  let flashesThatFeature;
+  if (wikiInfo.enableFlashesAndGames) {
+    flashesThatFeature = sortChronologically(
+      [track, ...otherReleases].flatMap((track) =>
+        track.featuredInFlashes.map((flash) => ({
+          flash,
+          as: track,
+          directory: flash.directory,
+          name: flash.name,
+          date: flash.date,
+        }))
+      )
+    );
+  }
 
-    const unbound_generateTrackList = (tracks, {getArtistString, link, language}) => html.tag('ul',
-        tracks.map(track => unbound_getTrackItem(track, {getArtistString, link, language}))
+  const unbound_getTrackItem = (track, {getArtistString, link, language}) =>
+    html.tag(
+      'li',
+      language.$('trackList.item.withArtists', {
+        track: link.track(track),
+        by: `<span class="by">${language.$('trackList.item.withArtists.by', {
+          artists: getArtistString(track.artistContribs),
+        })}</span>`,
+      })
     );
 
-    const hasCommentary = track.commentary || otherReleases.some(t => t.commentary);
-    const generateCommentary = ({
-        link,
-        language,
-        transformMultiline
-    }) => transformMultiline([
+  const hasCommentary =
+    track.commentary || otherReleases.some((t) => t.commentary);
+  const generateCommentary = ({link, language, transformMultiline}) =>
+    transformMultiline(
+      [
         track.commentary,
-        ...otherReleases.map(track =>
-            (track.commentary?.split('\n')
-                .filter(line => line.replace(/<\/b>/g, '').includes(':</i>'))
-                .map(line => fixWS`
+        ...otherReleases.map((track) =>
+          track.commentary
+            ?.split('\n')
+            .filter((line) => line.replace(/<\/b>/g, '').includes(':</i>'))
+            .map(
+              (line) => fixWS`
                     ${line}
-                    ${language.$('releaseInfo.artistCommentary.seeOriginalRelease', {
-                        original: link.track(track)
-                    })}
-                `)
-                .join('\n')))
-    ].filter(Boolean).join('\n'));
+                    ${language.$(
+                      'releaseInfo.artistCommentary.seeOriginalRelease',
+                      {
+                        original: link.track(track),
+                      }
+                    )}
+                `
+            )
+            .join('\n')
+        ),
+      ]
+        .filter(Boolean)
+        .join('\n')
+    );
 
-    const data = {
-        type: 'data',
-        path: ['track', track.directory],
-        data: ({
-            serializeContribs,
-            serializeCover,
-            serializeGroupsForTrack,
-            serializeLink
-        }) => ({
-            name: track.name,
-            directory: track.directory,
-            dates: {
-                released: track.date,
-                originallyReleased: track.originalDate,
-                coverArtAdded: track.coverArtDate
-            },
-            duration: track.duration,
-            color: track.color,
-            cover: serializeCover(track, getTrackCover),
-            artistsContribs: serializeContribs(track.artistContribs),
-            contributorContribs: serializeContribs(track.contributorContribs),
-            coverArtistContribs: serializeContribs(track.coverArtistContribs || []),
-            album: serializeLink(track.album),
-            groups: serializeGroupsForTrack(track),
-            references: track.references.map(serializeLink),
-            referencedBy: track.referencedBy.map(serializeLink),
-            alsoReleasedAs: otherReleases.map(track => ({
-                track: serializeLink(track),
-                album: serializeLink(track.album)
-            }))
-        })
-    };
+  const data = {
+    type: 'data',
+    path: ['track', track.directory],
+    data: ({
+      serializeContribs,
+      serializeCover,
+      serializeGroupsForTrack,
+      serializeLink,
+    }) => ({
+      name: track.name,
+      directory: track.directory,
+      dates: {
+        released: track.date,
+        originallyReleased: track.originalDate,
+        coverArtAdded: track.coverArtDate,
+      },
+      duration: track.duration,
+      color: track.color,
+      cover: serializeCover(track, getTrackCover),
+      artistsContribs: serializeContribs(track.artistContribs),
+      contributorContribs: serializeContribs(track.contributorContribs),
+      coverArtistContribs: serializeContribs(track.coverArtistContribs || []),
+      album: serializeLink(track.album),
+      groups: serializeGroupsForTrack(track),
+      references: track.references.map(serializeLink),
+      referencedBy: track.referencedBy.map(serializeLink),
+      alsoReleasedAs: otherReleases.map((track) => ({
+        track: serializeLink(track),
+        album: serializeLink(track.album),
+      })),
+    }),
+  };
 
-    const getSocialEmbedDescription = ({
-        getArtistString: _getArtistString,
-        language,
-    }) => {
-        const hasArtists = (track.artistContribs?.length > 0);
-        const hasCoverArtists = (track.coverArtistContribs?.length > 0);
-        const getArtistString = contribs => _getArtistString(contribs, {
-            // We don't want to put actual HTML tags in social embeds (sadly
-            // they don't get parsed and displayed, generally speaking), so
-            // override the link argument so that artist "links" just show
-            // their names.
-            link: {artist: artist => artist.name}
-        });
-        if (!hasArtists && !hasCoverArtists) return '';
-        return language.formatString(
-            'trackPage.socialEmbed.body' + [
-                hasArtists && '.withArtists',
-                hasCoverArtists && '.withCoverArtists',
-            ].filter(Boolean).join(''),
-            Object.fromEntries([
-                hasArtists && ['artists', getArtistString(track.artistContribs)],
-                hasCoverArtists && ['coverArtists', getArtistString(track.coverArtistContribs)],
-            ].filter(Boolean)))
-    };
+  const getSocialEmbedDescription = ({
+    getArtistString: _getArtistString,
+    language,
+  }) => {
+    const hasArtists = track.artistContribs?.length > 0;
+    const hasCoverArtists = track.coverArtistContribs?.length > 0;
+    const getArtistString = (contribs) =>
+      _getArtistString(contribs, {
+        // We don't want to put actual HTML tags in social embeds (sadly
+        // they don't get parsed and displayed, generally speaking), so
+        // override the link argument so that artist "links" just show
+        // their names.
+        link: {artist: (artist) => artist.name},
+      });
+    if (!hasArtists && !hasCoverArtists) return '';
+    return language.formatString(
+      'trackPage.socialEmbed.body' +
+        [hasArtists && '.withArtists', hasCoverArtists && '.withCoverArtists']
+          .filter(Boolean)
+          .join(''),
+      Object.fromEntries(
+        [
+          hasArtists && ['artists', getArtistString(track.artistContribs)],
+          hasCoverArtists && [
+            'coverArtists',
+            getArtistString(track.coverArtistContribs),
+          ],
+        ].filter(Boolean)
+      )
+    );
+  };
 
-    const page = {
-        type: 'page',
-        path: ['track', track.directory],
-        page: ({
-            absoluteTo,
-            fancifyURL,
-            generateChronologyLinks,
-            generateCoverLink,
-            generatePreviousNextLinks,
-            generateTrackListDividedByGroups,
-            getAlbumStylesheet,
-            getArtistString,
-            getLinkThemeString,
-            getThemeString,
-            getTrackCover,
-            link,
-            language,
-            transformInline,
-            transformLyrics,
-            transformMultiline,
-            to,
-            urls,
-        }) => {
-            const getTrackItem = bindOpts(unbound_getTrackItem, {getArtistString, link, language});
-            const cover = getTrackCover(track);
+  const page = {
+    type: 'page',
+    path: ['track', track.directory],
+    page: ({
+      absoluteTo,
+      fancifyURL,
+      generateChronologyLinks,
+      generateCoverLink,
+      generatePreviousNextLinks,
+      generateTrackListDividedByGroups,
+      getAlbumStylesheet,
+      getArtistString,
+      getLinkThemeString,
+      getThemeString,
+      getTrackCover,
+      link,
+      language,
+      transformLyrics,
+      transformMultiline,
+      to,
+      urls,
+    }) => {
+      const getTrackItem = bindOpts(unbound_getTrackItem, {
+        getArtistString,
+        link,
+        language,
+      });
+      const cover = getTrackCover(track);
 
-            return {
-                title: language.$('trackPage.title', {track: track.name}),
-                stylesheet: getAlbumStylesheet(album, {to}),
-                theme: getThemeString(track.color, [
-                    `--album-directory: ${album.directory}`,
-                    `--track-directory: ${track.directory}`
-                ]),
+      return {
+        title: language.$('trackPage.title', {track: track.name}),
+        stylesheet: getAlbumStylesheet(album, {to}),
+        theme: getThemeString(track.color, [
+          `--album-directory: ${album.directory}`,
+          `--track-directory: ${track.directory}`,
+        ]),
 
-                socialEmbed: {
-                    heading: language.$('trackPage.socialEmbed.heading', {album: track.album.name}),
-                    headingLink: absoluteTo('localized.album', album.directory),
-                    title: language.$('trackPage.socialEmbed.title', {track: track.name}),
-                    description: getSocialEmbedDescription({getArtistString, language}),
-                    image: '/' + getTrackCover(track, {to: urls.from('shared.root').to}),
-                    color: track.color,
-                },
+        socialEmbed: {
+          heading: language.$('trackPage.socialEmbed.heading', {
+            album: track.album.name,
+          }),
+          headingLink: absoluteTo('localized.album', album.directory),
+          title: language.$('trackPage.socialEmbed.title', {
+            track: track.name,
+          }),
+          description: getSocialEmbedDescription({getArtistString, language}),
+          image: '/' + getTrackCover(track, {to: urls.from('shared.root').to}),
+          color: track.color,
+        },
 
-                // disabled for now! shifting banner position per height of page is disorienting
-                /*
+        // disabled for now! shifting banner position per height of page is disorienting
+        /*
                 banner: album.bannerArtistContribs.length && {
                     classes: ['dim'],
                     dimensions: album.bannerDimensions,
@@ -191,156 +215,239 @@ export function write(track, {wikiData}) {
                 },
                 */
 
-                main: {
-                    content: fixWS`
-                        ${cover && generateCoverLink({
+        main: {
+          content: fixWS`
+                        ${
+                          cover &&
+                          generateCoverLink({
                             src: cover,
                             alt: language.$('misc.alt.trackCover'),
-                            tags: track.artTags
-                        })}
-                        <h1>${language.$('trackPage.title', {track: track.name})}</h1>
+                            tags: track.artTags,
+                          })
+                        }
+                        <h1>${language.$('trackPage.title', {
+                          track: track.name,
+                        })}</h1>
                         <p>
                             ${[
-                                language.$('releaseInfo.by', {
-                                    artists: getArtistString(track.artistContribs, {
-                                        showContrib: true,
-                                        showIcons: true
-                                    })
+                              language.$('releaseInfo.by', {
+                                artists: getArtistString(track.artistContribs, {
+                                  showContrib: true,
+                                  showIcons: true,
                                 }),
-                                track.coverArtistContribs.length && language.$('releaseInfo.coverArtBy', {
-                                    artists: getArtistString(track.coverArtistContribs, {
-                                        showContrib: true,
-                                        showIcons: true
-                                    })
+                              }),
+                              track.coverArtistContribs.length &&
+                                language.$('releaseInfo.coverArtBy', {
+                                  artists: getArtistString(
+                                    track.coverArtistContribs,
+                                    {
+                                      showContrib: true,
+                                      showIcons: true,
+                                    }
+                                  ),
                                 }),
-                                track.date && language.$('releaseInfo.released', {
-                                    date: language.formatDate(track.date)
+                              track.date &&
+                                language.$('releaseInfo.released', {
+                                  date: language.formatDate(track.date),
                                 }),
-                                (track.coverArtDate &&
-                                    +track.coverArtDate !== +track.date &&
-                                    language.$('releaseInfo.artReleased', {
-                                        date: language.formatDate(track.coverArtDate)
-                                    })),
-                                track.duration && language.$('releaseInfo.duration', {
-                                    duration: language.formatDuration(track.duration)
-                                })
-                            ].filter(Boolean).join('<br>\n')}
+                              track.coverArtDate &&
+                                +track.coverArtDate !== +track.date &&
+                                language.$('releaseInfo.artReleased', {
+                                  date: language.formatDate(track.coverArtDate),
+                                }),
+                              track.duration &&
+                                language.$('releaseInfo.duration', {
+                                  duration: language.formatDuration(
+                                    track.duration
+                                  ),
+                                }),
+                            ]
+                              .filter(Boolean)
+                              .join('<br>\n')}
                         </p>
                         <p>${
-                            (track.urls?.length
-                                ? language.$('releaseInfo.listenOn', {
-                                    links: language.formatDisjunctionList(track.urls.map(url => fancifyURL(url, {language})))
-                                })
-                                : language.$('releaseInfo.listenOn.noLinks'))
+                          track.urls?.length
+                            ? language.$('releaseInfo.listenOn', {
+                                links: language.formatDisjunctionList(
+                                  track.urls.map((url) =>
+                                    fancifyURL(url, {language})
+                                  )
+                                ),
+                              })
+                            : language.$('releaseInfo.listenOn.noLinks')
                         }</p>
-                        ${otherReleases.length && fixWS`
+                        ${
+                          otherReleases.length &&
+                          fixWS`
                             <p>${language.$('releaseInfo.alsoReleasedAs')}</p>
                             <ul>
-                                ${otherReleases.map(track => fixWS`
-                                    <li>${language.$('releaseInfo.alsoReleasedAs.item', {
+                                ${otherReleases
+                                  .map(
+                                    (track) => fixWS`
+                                    <li>${language.$(
+                                      'releaseInfo.alsoReleasedAs.item',
+                                      {
                                         track: link.track(track),
-                                        album: link.album(track.album)
-                                    })}</li>
-                                `).join('\n')}
+                                        album: link.album(track.album),
+                                      }
+                                    )}</li>
+                                `
+                                  )
+                                  .join('\n')}
                             </ul>
-                        `}
-                        ${track.contributorContribs.length && fixWS`
+                        `
+                        }
+                        ${
+                          track.contributorContribs.length &&
+                          fixWS`
                             <p>${language.$('releaseInfo.contributors')}</p>
                             <ul>
-                                ${(track.contributorContribs
-                                    .map(contrib => `<li>${getArtistString([contrib], {
+                                ${track.contributorContribs
+                                  .map(
+                                    (contrib) =>
+                                      `<li>${getArtistString([contrib], {
                                         showContrib: true,
-                                        showIcons: true
-                                    })}</li>`)
-                                    .join('\n'))}
+                                        showIcons: true,
+                                      })}</li>`
+                                  )
+                                  .join('\n')}
                             </ul>
-                        `}
-                        ${referencedTracks.length && fixWS`
-                            <p>${language.$('releaseInfo.tracksReferenced', {track: `<i>${track.name}</i>`})}</p>
-                            ${html.tag('ul', referencedTracks.map(getTrackItem))}
-                        `}
-                        ${referencedByTracks.length && fixWS`
-                            <p>${language.$('releaseInfo.tracksThatReference', {track: `<i>${track.name}</i>`})}</p>
-                            ${generateTrackListDividedByGroups(referencedByTracks, {
+                        `
+                        }
+                        ${
+                          referencedTracks.length &&
+                          fixWS`
+                            <p>${language.$('releaseInfo.tracksReferenced', {
+                              track: `<i>${track.name}</i>`,
+                            })}</p>
+                            ${html.tag(
+                              'ul',
+                              referencedTracks.map(getTrackItem)
+                            )}
+                        `
+                        }
+                        ${
+                          referencedByTracks.length &&
+                          fixWS`
+                            <p>${language.$('releaseInfo.tracksThatReference', {
+                              track: `<i>${track.name}</i>`,
+                            })}</p>
+                            ${generateTrackListDividedByGroups(
+                              referencedByTracks,
+                              {
                                 getTrackItem,
                                 wikiData,
-                            })}
-                        `}
-                        ${wikiInfo.enableFlashesAndGames && flashesThatFeature.length && fixWS`
-                            <p>${language.$('releaseInfo.flashesThatFeature', {track: `<i>${track.name}</i>`})}</p>
+                              }
+                            )}
+                        `
+                        }
+                        ${
+                          wikiInfo.enableFlashesAndGames &&
+                          flashesThatFeature.length &&
+                          fixWS`
+                            <p>${language.$('releaseInfo.flashesThatFeature', {
+                              track: `<i>${track.name}</i>`,
+                            })}</p>
                             <ul>
-                                ${flashesThatFeature.map(({ flash, as }) => html.tag('li',
-                                    {class: as !== track && 'rerelease'},
-                                    (as === track
-                                        ? language.$('releaseInfo.flashesThatFeature.item', {
-                                            flash: link.flash(flash)
-                                        })
-                                        : language.$('releaseInfo.flashesThatFeature.item.asDifferentRelease', {
-                                            flash: link.flash(flash),
-                                            track: link.track(as)
-                                        })))).join('\n')}
+                                ${flashesThatFeature
+                                  .map(({flash, as}) =>
+                                    html.tag(
+                                      'li',
+                                      {class: as !== track && 'rerelease'},
+                                      as === track
+                                        ? language.$(
+                                            'releaseInfo.flashesThatFeature.item',
+                                            {
+                                              flash: link.flash(flash),
+                                            }
+                                          )
+                                        : language.$(
+                                            'releaseInfo.flashesThatFeature.item.asDifferentRelease',
+                                            {
+                                              flash: link.flash(flash),
+                                              track: link.track(as),
+                                            }
+                                          )
+                                    )
+                                  )
+                                  .join('\n')}
                             </ul>
-                        `}
-                        ${track.lyrics && fixWS`
+                        `
+                        }
+                        ${
+                          track.lyrics &&
+                          fixWS`
                             <p>${language.$('releaseInfo.lyrics')}</p>
                             <blockquote>
                                 ${transformLyrics(track.lyrics)}
                             </blockquote>
-                        `}
-                        ${hasCommentary && fixWS`
+                        `
+                        }
+                        ${
+                          hasCommentary &&
+                          fixWS`
                             <p>${language.$('releaseInfo.artistCommentary')}</p>
                             <blockquote>
-                                ${generateCommentary({link, language, transformMultiline})}
+                                ${generateCommentary({
+                                  link,
+                                  language,
+                                  transformMultiline,
+                                })}
                             </blockquote>
-                        `}
-                    `
-                },
+                        `
+                        }
+                    `,
+        },
 
-                sidebarLeft: generateAlbumSidebar(album, track, {
-                    fancifyURL,
-                    getLinkThemeString,
-                    link,
-                    language,
-                    transformMultiline,
-                    wikiData
-                }),
+        sidebarLeft: generateAlbumSidebar(album, track, {
+          fancifyURL,
+          getLinkThemeString,
+          link,
+          language,
+          transformMultiline,
+          wikiData,
+        }),
 
-                nav: {
-                    linkContainerClasses: ['nav-links-hierarchy'],
-                    links: [
-                        {toHome: true},
-                        {
-                            path: ['localized.album', album.directory],
-                            title: album.name
-                        },
-                        listTag === 'ol' ? {
-                            html: language.$('trackPage.nav.track.withNumber', {
-                                number: album.tracks.indexOf(track) + 1,
-                                track: link.track(track, {class: 'current', to})
-                            })
-                        } : {
-                            html: language.$('trackPage.nav.track', {
-                                track: link.track(track, {class: 'current', to})
-                            })
-                        },
-                    ].filter(Boolean),
-                    content: generateAlbumChronologyLinks(album, track, {generateChronologyLinks}),
-                    bottomRowContent: (album.tracks.length > 1 &&
-                        generateAlbumNavLinks(album, track, {
-                            generatePreviousNextLinks,
-                            language,
-                        })),
+        nav: {
+          linkContainerClasses: ['nav-links-hierarchy'],
+          links: [
+            {toHome: true},
+            {
+              path: ['localized.album', album.directory],
+              title: album.name,
+            },
+            listTag === 'ol'
+              ? {
+                  html: language.$('trackPage.nav.track.withNumber', {
+                    number: album.tracks.indexOf(track) + 1,
+                    track: link.track(track, {class: 'current', to}),
+                  }),
+                }
+              : {
+                  html: language.$('trackPage.nav.track', {
+                    track: link.track(track, {class: 'current', to}),
+                  }),
                 },
+          ].filter(Boolean),
+          content: generateAlbumChronologyLinks(album, track, {
+            generateChronologyLinks,
+          }),
+          bottomRowContent:
+            album.tracks.length > 1 &&
+            generateAlbumNavLinks(album, track, {
+              generatePreviousNextLinks,
+              language,
+            }),
+        },
 
-                secondaryNav: generateAlbumSecondaryNav(album, track, {
-                    language,
-                    link,
-                    getLinkThemeString,
-                }),
-            };
-        }
-    };
+        secondaryNav: generateAlbumSecondaryNav(album, track, {
+          language,
+          link,
+          getLinkThemeString,
+        }),
+      };
+    },
+  };
 
-    return [data, page];
+  return [data, page];
 }
-