« get me outta code hell

content: listArtistsByLatestContribution (stub) - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2023-07-04 11:37:07 -0300
committer(quasar) nebula <qznebula@protonmail.com>2023-07-04 11:37:07 -0300
commitad7c99605b2683c1426aacf857a6136130993815 (patch)
tree66693151a2bbff713bc1624ad247ca5a178f0790
parent96165a08d6eb6c527c8330c74a4b5a602f6f770b (diff)
content: listArtistsByLatestContribution (stub)
This doesn't quite include the updates to this listing discussed
in #199 and #208 yet. Flash contributions are divided into their
own list just like in the updated "by Contributions" listing, though.
-rw-r--r--src/content/dependencies/listArtistsByLatestContribution.js179
-rw-r--r--src/listing-spec.js153
2 files changed, 180 insertions, 152 deletions
diff --git a/src/content/dependencies/listArtistsByLatestContribution.js b/src/content/dependencies/listArtistsByLatestContribution.js
new file mode 100644
index 00000000..c0135dca
--- /dev/null
+++ b/src/content/dependencies/listArtistsByLatestContribution.js
@@ -0,0 +1,179 @@
+import {stitchArrays} from '../../util/sugar.js';
+import {
+  compareDates,
+  filterMultipleArrays,
+  getLatestDate,
+  sortAlphabetically,
+  sortMultipleArrays,
+} from '../../util/wiki-data.js';
+
+export default {
+  contentDependencies: ['generateListingPage', 'linkArtist'],
+  extraDependencies: ['html', 'language', 'wikiData'],
+
+  sprawl({artistData, wikiInfo}) {
+    return {
+      artistData,
+      enableFlashesAndGames: wikiInfo.enableFlashesAndGames,
+    };
+  },
+
+  query(sprawl, spec) {
+    const query = {
+      spec,
+      enableFlashesAndGames: sprawl.enableFlashesAndGames,
+    };
+
+    const queryContributionInfo = (artistsKey, datesKey, datelessArtistsKey, fn) => {
+      const artists = sortAlphabetically(sprawl.artistData.slice());
+      const dates = artists.map(artist => fn(artist));
+
+      const {removed: [datelessArtists]} =
+        filterMultipleArrays(artists, dates, (artist, date) => date);
+
+      sortMultipleArrays(artists, dates,
+        (a, b, dateA, dateB) =>
+          compareDates(dateA, dateB, {latestFirst: true}));
+
+      query[artistsKey] = artists;
+      query[datesKey] = dates.map(dateNumber => new Date(dateNumber));
+      query[datelessArtistsKey] = datelessArtists;
+    };
+
+    queryContributionInfo(
+      'artistsByTrackContributions',
+      'datesByTrackContributions',
+      'datelessArtistsByTrackContributions',
+      artist =>
+        getLatestDate([
+          ...artist.tracksAsContributor.map(track => +track.date),
+          ...artist.tracksAsArtist.map(track => +track.date),
+        ]));
+
+    queryContributionInfo(
+      'artistsByArtworkContributions',
+      'datesByArtworkContributions',
+      'datelessArtistsByArtworkContributions',
+      artist =>
+        getLatestDate([
+          // TODO: Per-artwork dates, see #90.
+          ...artist.tracksAsCoverArtist.map(track => +track.coverArtDate),
+          ...artist.albumsAsCoverArtist.map(album => +album.coverArtDate),
+          ...artist.albumsAsWallpaperArtist.map(album => +album.coverArtDate),
+          ...artist.albumsAsBannerArtist.map(album => +album.coverArtDate),
+        ]));
+
+    if (sprawl.enableFlashesAndGames) {
+      queryContributionInfo(
+        'artistsByFlashContributions',
+        'datesByFlashContributions',
+        'datelessArtistsByFlashContributions',
+        artist =>
+          getLatestDate([
+            ...artist.flashesAsContributor.map(flash => +flash.date),
+          ]));
+    }
+
+    return query;
+  },
+
+  relations(relation, query) {
+    const relations = {};
+
+    relations.page =
+      relation('generateListingPage', query.spec);
+
+    relations.artistLinksByTrackContributions =
+      query.artistsByTrackContributions
+        .map(artist => relation('linkArtist', artist));
+
+    relations.artistLinksByArtworkContributions =
+      query.artistsByArtworkContributions
+        .map(artist => relation('linkArtist', artist));
+
+    if (query.enableFlashesAndGames) {
+      relations.artistLinksByFlashContributions =
+        query.artistsByFlashContributions
+          .map(artist => relation('linkArtist', artist));
+    }
+
+    return relations;
+  },
+
+  data(query) {
+    const data = {};
+
+    data.enableFlashesAndGames = query.enableFlashesAndGames;
+
+    data.datesByTrackContributions = query.datesByTrackContributions;
+    data.datesByArtworkContributions = query.datesByArtworkContributions;
+
+    if (query.enableFlashesAndGames) {
+      data.datesByFlashContributions = query.datesByFlashContributions;
+    }
+
+    return data;
+  },
+
+  generate(data, relations, {html, language}) {
+    const lists = Object.fromEntries(
+      ([
+        ['tracks', [
+          relations.artistLinksByTrackContributions,
+          data.datesByTrackContributions,
+        ]],
+
+        ['artworks', [
+          relations.artistLinksByArtworkContributions,
+          data.datesByArtworkContributions,
+        ]],
+
+        data.enableFlashesAndGames &&
+          ['flashes', [
+            relations.artistLinksByFlashContributions,
+            data.datesByFlashContributions,
+          ]],
+      ]).filter(Boolean)
+        .map(([key, [artistLinks, dates]]) => [
+          key,
+          html.tag('ul',
+            stitchArrays({
+              artistLink: artistLinks,
+              date: dates,
+            }).map(({artistLink, date}) =>
+                html.tag('li',
+                  language.$('listingPage.listArtists.byLatest.item', {
+                    artist: artistLink,
+                    date: language.formatDate(date),
+                  })))),
+        ]));
+
+    return relations.page.slots({
+      type: 'custom',
+      content:
+        html.tag('div', {class: 'content-columns'}, [
+          html.tag('div', {class: 'column'}, [
+            html.tag('h2',
+              language.$('listingPage.misc.trackContributors')),
+
+            lists.tracks,
+          ]),
+
+          html.tag('div', {class: 'column'}, [
+            html.tag('h2',
+              language.$(
+                'listingPage.misc.artContributors')),
+
+            lists.artworks,
+
+            lists.flashes && [
+              html.tag('h2',
+                language.$('listingPage.misc.flashContributors')),
+
+              lists.flashes,
+            ],
+          ]),
+        ]),
+    });
+  },
+};
diff --git a/src/listing-spec.js b/src/listing-spec.js
index 352f89db..17cde53f 100644
--- a/src/listing-spec.js
+++ b/src/listing-spec.js
@@ -83,158 +83,7 @@ listingSpec.push({
 listingSpec.push({
   directory: 'artists/by-latest',
   stringsKey: 'listArtists.byLatest',
-
-  data({wikiData: {
-    albumData,
-    flashData,
-    trackData,
-    wikiInfo,
-  }}) {
-    const processContribs = values => {
-      const filteredValues = values
-        .filter(value => value.date && !empty(value.contribs));
-
-      const datedArtistLists = sortByDate(filteredValues)
-        .map(({
-          contribs,
-          date,
-        }) => ({
-          artists: contribs.map(({who}) => who),
-          date,
-        }));
-
-      const remainingArtists = new Set(datedArtistLists.flatMap(({artists}) => artists));
-      const artistEntries = [];
-
-      for (let i = datedArtistLists.length - 1; i >= 0; i--) {
-        const {artists, date} = datedArtistLists[i];
-        for (const artist of artists) {
-          if (!remainingArtists.has(artist))
-            continue;
-
-          remainingArtists.delete(artist);
-          artistEntries.push({
-            artist,
-            date,
-
-            // For sortChronologically!
-            directory: artist.directory,
-            name: artist.name,
-          });
-        }
-
-        // Early exit: If we've gotten every artist, there's no need to keep
-        // going.
-        if (remainingArtists.size === 0)
-          break;
-      }
-
-      return sortChronologically(artistEntries, {latestFirst: true});
-    };
-
-    // Tracks are super easy to sort because they only have one pertinent
-    // date: the date the track was released on.
-
-    const toTracks = processContribs(
-      trackData.map(({
-        artistContribs,
-        date,
-      }) => ({
-        contribs: artistContribs,
-        date,
-      })));
-
-    // Artworks are a bit more involved because there are multiple dates
-    // involved - cover artists correspond to one date, wallpaper artists to
-    // another, etc.
-
-    const toArtAndFlashes = processContribs([
-      ...trackData.map(({
-        coverArtistContribs,
-        coverArtDate,
-      }) => ({
-        contribs: coverArtistContribs,
-        date: coverArtDate,
-      })),
-
-      ...flashData
-        ? flashData.map(({
-            contributorContribs,
-            date,
-          }) => ({
-            contribs: contributorContribs,
-            date,
-          }))
-        : [],
-
-      ...albumData.flatMap(({
-        bannerArtistContribs,
-        coverArtistContribs,
-        coverArtDate,
-        date,
-        wallpaperArtistContribs,
-      }) => [
-        {
-          contribs: coverArtistContribs,
-          date: coverArtDate,
-        },
-        {
-          contribs: bannerArtistContribs,
-          date, // TODO: bannerArtDate (see issue #90)
-        },
-        {
-          contribs: wallpaperArtistContribs,
-          date, // TODO: wallpaperArtDate (see issue #90)
-        },
-      ]),
-    ]);
-
-    return {
-      toArtAndFlashes,
-      toTracks,
-
-      // (Ok we did it again.)
-      // This is a kinda naughty hack, 8ut like, it's the only place
-      // we'd 8e passing wikiData to html() otherwise, so like....
-      showAsFlashes: wikiInfo.enableFlashesAndGames,
-    };
-  },
-
-  html: (
-    {toTracks, toArtAndFlashes, showAsFlashes},
-    {html, language, link}
-  ) =>
-    html.tag('div', {class: 'content-columns'}, [
-      html.tag('div', {class: 'column'}, [
-        html.tag('h2',
-          language.$('listingPage.misc.trackContributors')),
-
-        html.tag('ul',
-          toTracks.map(({artist, date}) =>
-            html.tag('li',
-              language.$('listingPage.listArtists.byLatest.item', {
-                artist: link.artist(artist),
-                date: language.formatDate(date),
-              })))),
-      ]),
-
-      html.tag('div', {class: 'column'}, [
-        html.tag('h2',
-          language.$(
-            'listingPage.misc' +
-              (showAsFlashes
-                ? '.artAndFlashContributors'
-                : '.artContributors'))),
-
-        html.tag('ul',
-          toArtAndFlashes.map(({artist, date}) =>
-            html.tag('li',
-              language.$('listingPage.listArtists.byLatest.item', {
-                artist: link.artist(artist),
-                date: language.formatDate(date),
-              })))),
-      ]),
-    ]),
+  contentFunction: 'listArtistsByLatestContribution',
 });
 
 listingSpec.push({