import { CopyButton } from "@/app/components/copy-button"; import { ErrorCard } from "@/app/components/error-card"; import { LookupServer } from "@/app/components/server/lookup-server"; import { ServerView } from "@/app/components/server/server-view"; import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger } from "@/app/components/ui/context-menu"; import { Colors } from "@/app/common/colors"; import { generateEmbed } from "@/app/common/embed"; import { formatNumber } from "@/app/common/number-utils"; import { isValidServer } from "@/app/common/server"; import { capitalizeFirstLetter } from "@/app/common/string-utils"; import config from "@root/config.json"; import { CachedBedrockMinecraftServer, CachedJavaMinecraftServer, getServer, McUtilsAPIError, ServerPlatform, } from "mcutils-library"; import { Metadata, Viewport } from "next"; import { ReactElement } from "react"; import { Title } from "@/app/components/title"; /** * Force the page to be dynamic, so it will be regenerated on every request */ export const revalidate = 0; type Params = { params: { platform: ServerPlatform; hostname: string; }; }; /** * Gets the favicon for a server * * @param platform the platform of the server * @param server the server to get the favicon from * @returns the favicon url or null if there is no favicon */ function getFavicon( platform: ServerPlatform | null, server: CachedJavaMinecraftServer | CachedBedrockMinecraftServer | undefined, ): string | undefined { if (server == null || platform === ServerPlatform.Bedrock) { return config.apiEndpoint + "/server/icon/fallback"; } server = server as CachedJavaMinecraftServer; return server.favicon && server.favicon.url; } /** * Checks if a platform is valid * * @param platform the platform to check * @returns true if the platform is valid, false otherwise */ function checkPlatform(platform: ServerPlatform): boolean { return platform === ServerPlatform.Java || platform === ServerPlatform.Bedrock; } export async function generateViewport({ params: { platform, hostname } }: Params): Promise { const validPlayer = await isValidServer(platform, hostname); return { themeColor: validPlayer || !platform ? Colors.green : Colors.red, }; } export async function generateMetadata({ params: { platform, hostname } }: Params): Promise { if (!checkPlatform(platform)) { // Invalid platform return generateEmbed({ title: "Server Not Found", description: "Invalid platform", }); } if (!hostname || hostname.length === 0) { // No hostname return generateEmbed({ title: "Server Lookup", description: `Click to lookup a ${capitalizeFirstLetter(platform)} server.`, }); } try { const server = await getServer(platform, hostname); const { hostname: serverHostname, players } = server; const favicon = getFavicon(platform, server); let description = `There is ${formatNumber(players.online)}/${formatNumber(players.max)} players connected!\n\n`; description += "Click to view more information about the server."; return generateEmbed({ title: `${serverHostname} ${capitalizeFirstLetter(platform)} Server`, embedTitle: `${capitalizeFirstLetter(platform)} Server: ${serverHostname}`, description: description, image: favicon, }); } catch (err) { // An error occurred return generateEmbed({ title: "Server Not Found", description: (err as McUtilsAPIError).message, }); } } export default async function Page({ params: { platform, hostname } }: Params): Promise { let error: string | undefined = undefined; // The error to display let server: CachedJavaMinecraftServer | CachedBedrockMinecraftServer | undefined = undefined; // The server to display let invalidPlatform: boolean = !checkPlatform(platform); // Whether the platform is invalid let favicon: string | undefined; // The server's favicon if (invalidPlatform) { error = "Invalid platform"; // Set the error message } else { // Try and get the player to display try { server = platform && hostname ? await getServer(platform, hostname) : undefined; favicon = getFavicon(platform, server); } catch (err) { error = (err as McUtilsAPIError).message; // Set the error message } } return (
<LookupServer currentPlatform={platform.toLowerCase()} currentServer={hostname && hostname[0]} /> </div> {error && <ErrorCard message={error} />} {server != null && ( <ContextMenu> <ContextMenuTrigger asChild> <ServerView server={server} favicon={favicon} /> </ContextMenuTrigger> <ContextMenuContent className="flex flex-col"> <CopyButton content={server.hostname}> <ContextMenuItem>Copy Server Hostname</ContextMenuItem> </CopyButton> {favicon && ( <CopyButton content={favicon}> <ContextMenuItem>Copy Server Favicon URL</ContextMenuItem> </CopyButton> )} </ContextMenuContent> </ContextMenu> )} </div> ); }