mod-bot/src/modules/commands/generateProfileImage.ts
2024-05-12 01:52:39 -07:00

214 lines
5.3 KiB
TypeScript

import { levels } from "@prisma/client";
import { AttachmentBuilder } from "discord.js";
import nodeHtmlToImage from "node-html-to-image";
import { ExtendedClient } from "../../interfaces/ExtendedClient";
import { errorHandler } from "../../utils/errorHandler";
/**
* Creates an image from the user's profile settings, converts it into a Discord
* attachment, and returns it.
*
* @param {ExtendedClient} CamperChan The CamperChan's Discord instance.
* @param {levels} record The user's record from the database.
* @returns {AttachmentBuilder} The attachment, or null on error.
*/
export const generateProfileImage = async (
CamperChan: ExtendedClient,
record: levels
): Promise<AttachmentBuilder | null> => {
try {
const {
avatar,
backgroundColour,
backgroundImage,
colour,
username,
level,
points
} = record;
const html = `
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
@font-face {
font-family: "Roboto";
src: url("https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700");
}
body {
background: url(${backgroundImage}) no-repeat center center fixed;
background-size: cover;
width: 1920px;
height: 1080px;
text-align: center;
font-family: "Roboto", Courier, monospace;
font-size: 75px;
padding: 2.5%;
}
h1 {
font-size: 150px;
}
main {
width: 100%;
height: 100%;
background-color: #${backgroundColour}bf;
color: #${colour};
padding: 2.5%;
border-radius: 100px;
}
.avatar {
width: 250px;
height: 250px;
border-radius: 50%;
}
h2 {
font-size: 125px;
}
.header {
width: 100%;
display: grid;
grid-template-columns: 250px auto;
justify-items: center;
align-items: center;
}
</style>
<body>
<main>
<div class="header">
<img class="avatar" src=${avatar || "https://cdn.freecodecamp.org/platform/universal/fcc_puck_500.jpg"}></img>
<div>
<h1>${username}</h1>
<p>Level ${level} (${points.toLocaleString("en-GB")}xp)</p>
</div>
</div>
</main>
</body>
`;
const alt = `${username} is at level ${level} with ${points.toLocaleString("en-GB")} experience points.`;
const image = await nodeHtmlToImage({
html,
selector: "body",
transparent: true
});
if (!(image instanceof Buffer)) {
return null;
}
const attachment = new AttachmentBuilder(image, {
name: `${username}.png`,
description: alt
});
return attachment;
} catch (err) {
await errorHandler(CamperChan, "generate profile image module", err);
return null;
}
};
/**
* Generates the image for the leaderboard.
*
* @param {ExtendedClient} CamperChan The CamperChan's Discord instance.
* @param {levels} levels The user's record from the database.
* @returns {AttachmentBuilder} The attachment, or null on error.
*/
export const generateLeaderboardImage = async (
CamperChan: ExtendedClient,
levels: (levels & { index: number })[]
): Promise<AttachmentBuilder | null> => {
try {
const html = `
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
@font-face {
font-family: "Roboto";
src: url("https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700");
}
body {
background: transparent;
height: 4100px;
width: 2510px;
}
img {
width: 250px;
height: 250px;
}
h1 {
font-size: 150px;
}
p {
font-size: 100px;
font-weight: bold;
}
.row {
width: 2500px;
display: grid;
grid-template-columns: 250px 2250px;
height: 400px;
margin: 5px 10px;
justify-items: left;
align-items: center;
}
</style>
<body>
${levels.map(
(l) =>
`<div class="row" style="background-color: #${l.backgroundColour || "0a0a23"}bf;color: #${l.colour || "d0d0d5"};padding: 2.5%;border-radius: 100px;">
<img style="border-radius: 50%;" src=${l.avatar || "https://cdn.freecodecamp.org/platform/universal/fcc_puck_500.jpg"}></img>
<div style="text-align: left;padding-left:100px;">
<h1>#${l.index}. ${l.username}</h1>
<p>Level ${l.level} (${l.points}xp)</p>
</div>
</div>`
)}
</body>
`;
const alt = levels
.map(
(l) =>
`${l.username} is rank ${l.index} at ${l.level} with ${l.points.toLocaleString("en-GB")} experience points.`
)
.join(", ");
const image = await nodeHtmlToImage({
html,
selector: "body",
transparent: true
});
if (!(image instanceof Buffer)) {
return null;
}
const attachment = new AttachmentBuilder(image, {
name: `leaderboard-${levels[0]?.index}.png`,
description: alt
});
return attachment;
} catch (err) {
await errorHandler(CamperChan, "generate leaderboard image module", err);
return null;
}
};