From f3d84f3c55734bf41bd630a50e4f97d1b980e645 Mon Sep 17 00:00:00 2001 From: Dylan Pizzo Date: Sun, 14 Jun 2026 22:23:37 -0400 Subject: [PATCH] display cart images --- src/client/AuthorPage.tsx | 25 +++++++++++++---- src/server/api/getAuthor.ts | 20 +++++++++---- src/server/util/getData.ts | 56 +++++++++++++++++++++++++++++++++++++ src/server/util/types.ts | 1 + 4 files changed, 90 insertions(+), 12 deletions(-) create mode 100644 src/server/util/getData.ts create mode 100644 src/server/util/types.ts 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 }[] };