2021-07-02 14:34:30 -07:00
|
|
|
import React from "react";
|
|
|
|
|
import { Box, Center } from "@chakra-ui/react";
|
|
|
|
|
import * as Sentry from "@sentry/react";
|
2021-07-02 15:19:11 -07:00
|
|
|
import { Global, css } from "@emotion/react";
|
2022-09-14 19:27:26 -07:00
|
|
|
import { useRouter } from "next/router";
|
2021-07-02 15:19:11 -07:00
|
|
|
|
2021-07-02 14:34:30 -07:00
|
|
|
import OutfitMovieLayer from "./components/OutfitMovieLayer";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* We use this in /api/assetImage, to render the asset image! The headless
|
|
|
|
|
* browser navigates here, and screenshots the canvas once it loads.
|
|
|
|
|
*/
|
|
|
|
|
function InternalAssetImagePage() {
|
|
|
|
|
return (
|
|
|
|
|
<Box padding="4">
|
|
|
|
|
<Sentry.ErrorBoundary
|
|
|
|
|
fallback={({ error }) => (
|
|
|
|
|
<AssetImageErrorMessage>
|
|
|
|
|
Unexpected error: {error.message}
|
|
|
|
|
</AssetImageErrorMessage>
|
|
|
|
|
)}
|
|
|
|
|
>
|
|
|
|
|
<InternalAssetImagePageContent />
|
|
|
|
|
</Sentry.ErrorBoundary>
|
2021-07-02 15:19:11 -07:00
|
|
|
<Global
|
|
|
|
|
// We remove the default body background, so that the headless browser
|
|
|
|
|
// can take the screenshot with transparency.
|
|
|
|
|
styles={css`
|
|
|
|
|
body {
|
|
|
|
|
background: transparent;
|
|
|
|
|
}
|
|
|
|
|
`}
|
|
|
|
|
/>
|
2021-07-02 14:34:30 -07:00
|
|
|
</Box>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function InternalAssetImagePageContent() {
|
2022-09-14 19:27:26 -07:00
|
|
|
const { query } = useRouter();
|
|
|
|
|
const libraryUrl = query.libraryUrl;
|
|
|
|
|
const size = query.size ?? "600";
|
2021-07-02 14:34:30 -07:00
|
|
|
|
|
|
|
|
const [movieError, setMovieError] = React.useState(null);
|
|
|
|
|
|
|
|
|
|
const onMovieError = React.useCallback((error) => {
|
|
|
|
|
console.error("Error playing movie:", error);
|
|
|
|
|
setMovieError(error);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
if (!libraryUrl) {
|
|
|
|
|
return (
|
|
|
|
|
<AssetImageErrorMessage>
|
|
|
|
|
Error: libraryUrl parameter is required
|
|
|
|
|
</AssetImageErrorMessage>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!isNeopetsUrl(libraryUrl)) {
|
|
|
|
|
return (
|
|
|
|
|
<AssetImageErrorMessage>
|
|
|
|
|
Error: libraryUrl must be an HTTPS Neopets URL, but was:{" "}
|
|
|
|
|
<code>{JSON.stringify(libraryUrl)}</code>
|
|
|
|
|
</AssetImageErrorMessage>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-19 17:56:09 -07:00
|
|
|
if (size !== "600" && size !== "300" && size !== "150") {
|
|
|
|
|
return (
|
|
|
|
|
<AssetImageErrorMessage>
|
|
|
|
|
Error: size must be 600, 300, or 150, but was: {size}
|
|
|
|
|
</AssetImageErrorMessage>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-02 14:34:30 -07:00
|
|
|
if (movieError) {
|
|
|
|
|
return (
|
|
|
|
|
<AssetImageErrorMessage>
|
|
|
|
|
Error playing movie: {movieError.message}
|
|
|
|
|
</AssetImageErrorMessage>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
2021-08-19 17:56:09 -07:00
|
|
|
<Box
|
|
|
|
|
border="1px solid"
|
|
|
|
|
borderColor="green.400"
|
|
|
|
|
boxSizing="content-box"
|
|
|
|
|
width={parseInt(size)}
|
|
|
|
|
height={parseInt(size)}
|
|
|
|
|
>
|
2021-07-02 14:34:30 -07:00
|
|
|
<OutfitMovieLayer
|
|
|
|
|
libraryUrl={libraryUrl}
|
2021-08-19 17:56:09 -07:00
|
|
|
width={parseInt(size)}
|
|
|
|
|
height={parseInt(size)}
|
2021-07-02 14:34:30 -07:00
|
|
|
onError={onMovieError}
|
|
|
|
|
canvasProps={{ id: "asset-image-canvas" }}
|
|
|
|
|
isPaused
|
|
|
|
|
/>
|
|
|
|
|
</Box>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isNeopetsUrl(urlString) {
|
|
|
|
|
let url;
|
|
|
|
|
try {
|
|
|
|
|
url = new URL(urlString);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return url.origin === "https://images.neopets.com";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function AssetImageErrorMessage({ children }) {
|
|
|
|
|
return (
|
|
|
|
|
<Center
|
|
|
|
|
width="600px"
|
|
|
|
|
height="600px"
|
|
|
|
|
color="red.400"
|
|
|
|
|
border="1px solid"
|
|
|
|
|
borderColor="red.400"
|
|
|
|
|
textAlign="center"
|
|
|
|
|
padding="4"
|
|
|
|
|
id="asset-image-error-message"
|
|
|
|
|
>
|
|
|
|
|
<Box>{children}</Box>
|
|
|
|
|
</Center>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default InternalAssetImagePage;
|