display cart images
This commit is contained in:
@@ -1,11 +1,12 @@
|
|||||||
import { Link, useParams } from "react-router-dom";
|
import { Link, useParams } from "react-router-dom";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { css } from "@emotion/css";
|
import { css } from "@emotion/css";
|
||||||
|
import { Game } from "../server/util/types";
|
||||||
// import { type Pico8Player } from "@athingperday/react-pico-player";
|
// import { type Pico8Player } from "@athingperday/react-pico-player";
|
||||||
|
|
||||||
type Info = {
|
type Info = {
|
||||||
author: string | null;
|
author: string | null;
|
||||||
games: string[];
|
games: Game[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AuthorPage = () => {
|
export const AuthorPage = () => {
|
||||||
@@ -44,11 +45,23 @@ export const AuthorPage = () => {
|
|||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
<h1>{author}</h1>
|
<h1>{author}</h1>
|
||||||
|
<div
|
||||||
|
className={css`
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
`}
|
||||||
|
>
|
||||||
{info.games.map((game) => (
|
{info.games.map((game) => (
|
||||||
<Link key={game} to={`/u/${author}/${game}`}>
|
<Link
|
||||||
<h3>{game}</h3>
|
key={game.carts[0].name}
|
||||||
|
to={`/u/${author}/${game.carts[0].name}`}
|
||||||
|
>
|
||||||
|
<h3>
|
||||||
|
<img src={game.carts[0].src} />
|
||||||
|
</h3>
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { FirRouteInput, FirRouteOptions } from "../util/routewrap.ts";
|
|||||||
import { authors } from "../../data/authors.ts";
|
import { authors } from "../../data/authors.ts";
|
||||||
import { Octokit } from "octokit";
|
import { Octokit } from "octokit";
|
||||||
import { decrypt } from "../util/crypt.ts";
|
import { decrypt } from "../util/crypt.ts";
|
||||||
|
import { Game } from "../util/types.ts";
|
||||||
|
import { getGame, getGameFromSha } from "../util/getData.ts";
|
||||||
|
|
||||||
const method = "GET";
|
const method = "GET";
|
||||||
const url = "/api/author";
|
const url = "/api/author";
|
||||||
@@ -38,15 +40,21 @@ const handler = async ({ payload }: FirRouteInput<typeof payloadT>) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// TODO: get the games.
|
// TODO: get the games.
|
||||||
const games: string[] = [];
|
const games: Game[] = [];
|
||||||
|
|
||||||
if (Array.isArray(gameStuff.data)) {
|
if (Array.isArray(gameStuff.data)) {
|
||||||
games.push(
|
const newGames = await Promise.all(
|
||||||
...gameStuff.data
|
gameStuff.data
|
||||||
.map((x) => x.name)
|
.filter((x) => x.name.endsWith(".p8.png") && x.type === "file")
|
||||||
.filter((x) => x.endsWith(".p8.png"))
|
.flatMap(async (x) => {
|
||||||
.map((x) => x.slice(0, -".p8.png".length)),
|
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 {
|
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