diff --git a/api/assetImage.js b/api/assetImage.js index 69aaa51..cf9d82d 100644 --- a/api/assetImage.js +++ b/api/assetImage.js @@ -7,6 +7,10 @@ * a bit slow, and consume significant RAM. So, caching is going to be * important, so that we're not calling this all the time and overloading the * endpoint! + * + * Parameters: + * - libraryUrl: A https://images.neopets.com/ URL to a JS movie library + * - size: 600, 300, or 150. Determines the output image size. */ const beeline = require("honeycomb-beeline")({ writeKey: process.env["HONEYCOMB_WRITE_KEY"], @@ -53,7 +57,7 @@ async function getBrowser() { } async function handle(req, res) { - const { libraryUrl } = req.query; + const { libraryUrl, size } = req.query; if (!libraryUrl) { return reject(res, "libraryUrl is required"); } @@ -65,9 +69,13 @@ async function handle(req, res) { ); } + if (size !== "600" && size !== "300" && size !== "150") { + return reject(res, `size must be 600, 300, or 150, but was: ${size}`); + } + let imageBuffer; try { - imageBuffer = await loadAndScreenshotImage(libraryUrl); + imageBuffer = await loadAndScreenshotImage(libraryUrl, size); } catch (e) { console.error(e); return reject(res, `Could not load image: ${e.message}`, 500); @@ -82,9 +90,12 @@ async function handle(req, res) { return res.send(imageBuffer); } -async function loadAndScreenshotImage(libraryUrl) { +async function loadAndScreenshotImage(libraryUrl, size) { const assetImagePageUrl = new URL(ASSET_IMAGE_PAGE_BASE_URL); - assetImagePageUrl.search = new URLSearchParams({ libraryUrl }).toString(); + assetImagePageUrl.search = new URLSearchParams({ + libraryUrl, + size, + }).toString(); console.debug("Opening browser page"); const browser = await getBrowser(); diff --git a/src/app/InternalAssetImagePage.js b/src/app/InternalAssetImagePage.js index 2d3aa1b..c9db2b8 100644 --- a/src/app/InternalAssetImagePage.js +++ b/src/app/InternalAssetImagePage.js @@ -39,6 +39,7 @@ function InternalAssetImagePageContent() { const location = useLocation(); const search = new URLSearchParams(location.search); const libraryUrl = search.get("libraryUrl"); + const size = search.get("size") || "600"; const [movieError, setMovieError] = React.useState(null); @@ -64,6 +65,14 @@ function InternalAssetImagePageContent() { ); } + if (size !== "600" && size !== "300" && size !== "150") { + return ( + + Error: size must be 600, 300, or 150, but was: {size} + + ); + } + if (movieError) { return ( @@ -73,11 +82,17 @@ function InternalAssetImagePageContent() { } return ( - + { const layer = await swfAssetLoader.load(id); - // For the largest size, try to use the official Neopets PNG! - // - // NOTE: This is mainly to avoid cases where the official PNG, based on - // the official SWF, is inaccurate. (This was the case for the - // Flying in an Airplane item when it first released, with the - // OFFICIAL_SVG_IS_INCORRECT glitch.) - // - // TODO: This doesn't really help us with the glitches in our own PNGs, - // because 1) if an official PNG is available, an official SVG - // probably is too, and we prefer to use that in most cases; and 2) - // outfit image thumbnails currently only request 300x300 at most, - // so we'll still use our own PNGs for those cases. - if (size === "SIZE_600") { - const { - format, - jsAssetUrl, - pngAssetUrl, - } = await loadAndCacheAssetDataFromManifest(db, layer); + const { + format, + jsAssetUrl, + pngAssetUrl, + } = await loadAndCacheAssetDataFromManifest(db, layer); + // For the largest size, try to use the official Neopets PNG! + // TODO: Offer an API endpoint to resize the official Neopets PNG maybe? + // That'll be an important final step before turning off the + // Classic DTI image converters. + if (size === "SIZE_600") { // If there's an official single-image PNG we can use, use it! This is // what the official /customise editor uses at time of writing. if (format === "lod" && !jsAssetUrl && pngAssetUrl) { return pngAssetUrl.toString(); } + } - // Or, if this is a movie, we can generate the PNG ourselves. - // TODO: Support this for smaller image sizes, too. - if (format === "lod" && jsAssetUrl) { - const httpsJsAssetUrl = jsAssetUrl - .toString() - .replace(/^http:\/\//, "https://"); - return ( - `https://impress-2020.openneo.net/api/assetImage` + - `?libraryUrl=${encodeURIComponent(httpsJsAssetUrl)}` - ); - } + // Or, if this is a movie, we can generate the PNG ourselves. + if (format === "lod" && jsAssetUrl) { + const httpsJsAssetUrl = jsAssetUrl + .toString() + .replace(/^http:\/\//, "https://"); + const sizeNum = size.split("_")[1]; + return ( + `https://impress-2020.openneo.net/api/assetImage` + + `?libraryUrl=${encodeURIComponent(httpsJsAssetUrl)}&size=${sizeNum}` + ); } // Otherwise, fall back to the Classic DTI image storage, which is