display cart images
This commit is contained in:
@@ -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 = () => {
|
||||
`}
|
||||
>
|
||||
<h1>{author}</h1>
|
||||
<div
|
||||
className={css`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
`}
|
||||
>
|
||||
{info.games.map((game) => (
|
||||
<Link key={game} to={`/u/${author}/${game}`}>
|
||||
<h3>{game}</h3>
|
||||
<Link
|
||||
key={game.carts[0].name}
|
||||
to={`/u/${author}/${game.carts[0].name}`}
|
||||
>
|
||||
<h3>
|
||||
<img src={game.carts[0].src} />
|
||||
</h3>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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<typeof payloadT>) => {
|
||||
});
|
||||
|
||||
// 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 {
|
||||
|
||||
@@ -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<string, Game> = {};
|
||||
|
||||
export const getGame = async (
|
||||
author: string,
|
||||
name: string,
|
||||
): Promise<Game | null> => {
|
||||
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<Game | null> => {
|
||||
if (gameCache[sha]) {
|
||||
console.log("cache hit");
|
||||
}
|
||||
return gameCache[sha] ?? null;
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export type Game = { carts: { name: string; src: string }[] };
|
||||
Reference in New Issue
Block a user