diff --git a/projects/backend/components/globe-icon.tsx b/projects/backend/components/globe-icon.tsx new file mode 100644 index 0000000..26768e5 --- /dev/null +++ b/projects/backend/components/globe-icon.tsx @@ -0,0 +1,20 @@ +import React from "react"; + +export const GlobeIcon = () => ( + + + +); diff --git a/projects/backend/components/star-icon.tsx b/projects/backend/components/star-icon.tsx new file mode 100644 index 0000000..7c03014 --- /dev/null +++ b/projects/backend/components/star-icon.tsx @@ -0,0 +1,20 @@ +import React from "react"; + +export const StarIcon = () => ( + + + +); diff --git a/projects/backend/package.json b/projects/backend/package.json index a051333..f5e5e26 100644 --- a/projects/backend/package.json +++ b/projects/backend/package.json @@ -13,7 +13,6 @@ "@elysiajs/swagger": "^1.1.3", "@ssr/common": "workspace:common", "@tqman/nice-logger": "^1.0.1", - "@typegoose/typegoose": "^12.8.0", "@vercel/og": "^0.6.3", "elysia": "latest", "elysia-autoroutes": "^0.5.0", diff --git a/projects/backend/src/service/image.service.tsx b/projects/backend/src/service/image.service.tsx index e567ce0..dcf6005 100644 --- a/projects/backend/src/service/image.service.tsx +++ b/projects/backend/src/service/image.service.tsx @@ -2,15 +2,39 @@ import { ImageResponse } from "@vercel/og"; import { scoresaberService } from "@ssr/common/service/impl/scoresaber"; import React from "react"; import { formatNumberWithCommas, formatPp } from "@ssr/common/utils/number-utils"; -import NodeCache from "node-cache"; import { getDifficultyFromScoreSaberDifficulty } from "@ssr/common/utils/scoresaber-utils"; +import { StarIcon } from "../../components/star-icon"; +import { GlobeIcon } from "../../components/globe-icon"; +import NodeCache from "node-cache"; +import ScoreSaberPlayerToken from "@ssr/common/types/token/scoresaber/score-saber-player-token"; +import ScoreSaberLeaderboardToken from "@ssr/common/types/token/scoresaber/score-saber-leaderboard-token"; -const imageCache = new NodeCache({ +const cache = new NodeCache({ stdTTL: 60 * 60, // 1 hour checkperiod: 120, }); export class ImageService { + /** + * The base of the OpenGraph image + * + * @param children the content of the image + * @private + */ + public static BaseImage({ children }: { children: React.ReactNode }) { + return ( +
+ {children} +
+ ); + } + /** * Generates the OpenGraph image for the player * @@ -18,45 +42,29 @@ export class ImageService { */ public static async generatePlayerImage(id: string) { const cacheKey = `player-${id}`; - if (imageCache.has(cacheKey)) { - return imageCache.get(cacheKey) as ImageResponse; + let player: undefined | ScoreSaberPlayerToken; + if (cache.has(cacheKey)) { + player = cache.get(cacheKey); + } else { + player = await scoresaberService.lookupPlayer(id); + if (player != undefined) { + cache.set(cacheKey, player); + } } - - const player = await scoresaberService.lookupPlayer(id); if (player == undefined) { return undefined; } - const imageResponse = new ImageResponse( + + return new ImageResponse( ( -
+ Player's Avatar

{player.name}

{formatPp(player.pp)}pp

- - - +

#{formatNumberWithCommas(player.rank)}

@@ -70,7 +78,7 @@ export class ImageService {
-
+ ), { width: 1200, @@ -78,8 +86,6 @@ export class ImageService { emoji: "twemoji", } ); - imageCache.set(cacheKey, imageResponse); - return imageResponse; } /** @@ -89,25 +95,23 @@ export class ImageService { */ public static async generateLeaderboardImage(id: string) { const cacheKey = `leaderboard-${id}`; - if (imageCache.has(cacheKey)) { - return imageCache.get(cacheKey) as ImageResponse; + let leaderboard: undefined | ScoreSaberLeaderboardToken; + if (cache.has(cacheKey)) { + leaderboard = cache.get(cacheKey) as ScoreSaberLeaderboardToken; + } else { + leaderboard = await scoresaberService.lookupLeaderboard(id); + if (leaderboard != undefined) { + cache.set(cacheKey, leaderboard); + } } - - const leaderboard = await scoresaberService.lookupLeaderboard(id); if (leaderboard == undefined) { return undefined; } const ranked = leaderboard.stars > 0; - const imageResponse = new ImageResponse( + return new ImageResponse( ( -
+ Player's Avatar

{leaderboard.songName} {leaderboard.songSubName} @@ -116,22 +120,7 @@ export class ImageService { {ranked && (

{leaderboard.stars}

- - - +
)}

@@ -139,7 +128,7 @@ export class ImageService {

Mapped by {leaderboard.levelAuthorName}

- + ), { width: 1200, @@ -147,8 +136,5 @@ export class ImageService { emoji: "twemoji", } ); - - imageCache.set(cacheKey, imageResponse); - return imageResponse; } }