diff --git a/src/client/AuthorPage.tsx b/src/client/AuthorPage.tsx
index 10aae79..eccad50 100644
--- a/src/client/AuthorPage.tsx
+++ b/src/client/AuthorPage.tsx
@@ -1,11 +1,12 @@
import { Link, useParams } from "react-router-dom";
import { useEffect, useState } from "react";
import { css } from "@emotion/css";
+import { Game } from "../server/util/types";
// import { type Pico8Player } from "@athingperday/react-pico-player";
type Info = {
author: string | null;
- games: string[];
+ games: Game[];
};
export const AuthorPage = () => {
@@ -44,11 +45,23 @@ export const AuthorPage = () => {
`}
>
{author}
- {info.games.map((game) => (
-
- {game}
-
- ))}
+
+ {info.games.map((game) => (
+
+
+
+
+
+ ))}
+
);
};
diff --git a/src/server/api/getAuthor.ts b/src/server/api/getAuthor.ts
index 5da1fc1..e633105 100644
--- a/src/server/api/getAuthor.ts
+++ b/src/server/api/getAuthor.ts
@@ -3,6 +3,8 @@ import { FirRouteInput, FirRouteOptions } from "../util/routewrap.ts";
import { authors } from "../../data/authors.ts";
import { Octokit } from "octokit";
import { decrypt } from "../util/crypt.ts";
+import { Game } from "../util/types.ts";
+import { getGame, getGameFromSha } from "../util/getData.ts";
const method = "GET";
const url = "/api/author";
@@ -38,15 +40,21 @@ const handler = async ({ payload }: FirRouteInput) => {
});
// TODO: get the games.
- const games: string[] = [];
+ const games: Game[] = [];
if (Array.isArray(gameStuff.data)) {
- games.push(
- ...gameStuff.data
- .map((x) => x.name)
- .filter((x) => x.endsWith(".p8.png"))
- .map((x) => x.slice(0, -".p8.png".length)),
+ const newGames = await Promise.all(
+ gameStuff.data
+ .filter((x) => x.name.endsWith(".p8.png") && x.type === "file")
+ .flatMap(async (x) => {
+ const name = x.name.slice(0, -".p8.png".length);
+ const game =
+ (await getGameFromSha(x.sha)) ??
+ (await getGame(authorData.username, name));
+ return game ? [game] : [];
+ }),
);
+ games.push(...newGames.flat());
}
return {
diff --git a/src/server/util/getData.ts b/src/server/util/getData.ts
new file mode 100644
index 0000000..db906b2
--- /dev/null
+++ b/src/server/util/getData.ts
@@ -0,0 +1,56 @@
+import { Octokit } from "octokit";
+import { decrypt } from "./crypt";
+import { authors } from "../../data/authors";
+
+type Game = { carts: { name: string; src: string }[] };
+
+const gameCache: Record = {};
+
+export const getGame = async (
+ author: string,
+ name: string,
+): Promise => {
+ const authorData = authors.find((x) => x.username === author);
+
+ if (!authorData) {
+ return null;
+ }
+
+ const pat = decrypt({
+ password: process.env.ENCRYPTION_PASSWORD!,
+ cyphertext: authorData.auth.pat,
+ });
+
+ const octokit = new Octokit({
+ auth: pat,
+ });
+
+ const gameData = (
+ await octokit.rest.repos.getContent({
+ owner: authorData.username,
+ repo: authorData.repo,
+ path: `.picobook/${name}.p8.png`,
+ })
+ ).data;
+
+ if (Array.isArray(gameData)) {
+ return null;
+ }
+ if (gameData.type !== "file") {
+ return null;
+ }
+
+ if (!(gameData.sha in gameCache)) {
+ gameCache[gameData.sha] = {
+ carts: [{ name, src: `data:image/png;base64,${gameData.content}` }],
+ };
+ }
+ return gameCache[gameData.sha];
+};
+
+export const getGameFromSha = async (sha: string): Promise => {
+ if (gameCache[sha]) {
+ console.log("cache hit");
+ }
+ return gameCache[sha] ?? null;
+};
diff --git a/src/server/util/types.ts b/src/server/util/types.ts
new file mode 100644
index 0000000..a94be7a
--- /dev/null
+++ b/src/server/util/types.ts
@@ -0,0 +1 @@
+export type Game = { carts: { name: string; src: string }[] };