Compare commits

...

10 Commits

Author SHA1 Message Date
a0b5be0633 Fixed a bug in a welcome message 2025-12-08 23:29:01 +01:00
3098a128d8 Add custom welcome messages with mention 2025-12-02 16:39:38 +01:00
2d7f13bb27 Enable onClientReady message 2025-12-02 13:03:09 +01:00
4bcdb4aa93 Fixed namecard fonts 2025-12-02 11:41:18 +01:00
fe4c03357a Fixed worker termination and result retrieving 2025-12-02 11:31:34 +01:00
ec9f14c9e7 Fixed stuff 2025-11-11 22:42:14 +01:00
e3218af147 Change shitty lib canvas for @napi-rs/canva 2025-11-11 21:31:34 +01:00
9cc2f7c169 Update name card tests 2025-11-11 19:50:25 +01:00
d1143cff12 Log some stuff 2025-11-11 19:24:44 +01:00
a302b6288e oopsie 2025-11-11 18:40:32 +01:00
8 changed files with 101 additions and 38 deletions

View File

@@ -8,9 +8,16 @@ RUN npm install
COPY . . COPY . .
RUN apt-get update && apt-get install -y fontconfig #Installing fonts
RUN apt-get update || true
RUN apt-get install -y --no-install-recommends \
gnupg \
ca-certificates \
fontconfig || true
RUN mkdir -p /usr/local/share/fonts/truetype/fredoka RUN mkdir -p /usr/local/share/fonts/truetype/fredoka
COPY ./wwwroot/assets/fonts/Fredoka/fredoka.ttf /usr/local/share/fonts/truetype/fredoka/fredoka.ttf COPY ./wwwroot/assets/fonts/Fredoka/fredoka.ttf /usr/local/share/fonts/truetype/fredoka/fredoka.ttf
RUN fc-cache -fv RUN fc-cache -fv
CMD ["npm", "run", "name-card-test"] CMD ["npm", "run", "start"]

27
bot.js
View File

@@ -3,6 +3,7 @@ import JsonManager from "./wwwroot/core/utils/jsonManager.js";
import {Logger} from "./wwwroot/core/logging/logger.js"; import {Logger} from "./wwwroot/core/logging/logger.js";
import {launchWorker} from "./wwwroot/core/namecards/workerLauncher.js"; import {launchWorker} from "./wwwroot/core/namecards/workerLauncher.js";
import {AttachmentBuilder} from "discord.js"; import {AttachmentBuilder} from "discord.js";
import StringFormatter from "./wwwroot/core/utils/stringFormatter.js";
const launch = async () => { const launch = async () => {
try{ try{
@@ -32,9 +33,20 @@ const launch = async () => {
}); });
data.client.on('guildMemberAdd', async (member) => { data.client.on('guildMemberAdd', async (member) => {
const possibleMessages = [
"<@:user> is one of us!",
"I know what you are, <@:user>...",
"Osmanthus wine tastes the same as I— oop, wrong line <@:user>",
"Yeah yeah, welcome or whatever <@:user>",
"OH. MY. GOD Y'ALL— <@:user> is here!",
"So... we're all seeing <@:user>, right?",
"<@:user> is right behind me, aren't they...?"
]
const choseMessage = possibleMessages[Math.floor(Math.random() * possibleMessages.length)];
try { try {
const avatarUrl = member.user.displayAvatarURL({ extension: 'png', size: 512 }); const avatarUrl = member.user.displayAvatarURL({ extension: 'png', size: 512 });
const username = member.displayName; const username = member.displayName || member.user.username;
const result = await launchWorker({ const result = await launchWorker({
templatePath: data.nameCardTemplate, templatePath: data.nameCardTemplate,
@@ -42,16 +54,23 @@ const launch = async () => {
username: username, username: username,
}); });
const attachment = new AttachmentBuilder(result, { name: 'namecard.png' }); const attachment = new AttachmentBuilder(Buffer.from(result.result), { name: 'namecard.png' });
const channel = await member.guild.channels.fetch(data.welcomeChannelID); const channel = await member.guild.channels.fetch(data.welcomeChannelID);
await channel.send({ files: [attachment] }); await channel.send({
content: StringFormatter.format(choseMessage, [ {key : "user", value : member.id} ]),
allowedMentions: {
users: [member.id]
},
files: [attachment]
});
} catch (err) { } catch (err) {
console.error('Failed to generate/send name card:', err); await Logger.error('Failed to generate/send name card:', err);
} }
}); });
process.on('SIGINT', async () => { process.on('SIGINT', async () => {
try { try {
await data.sender.send(data.updateChannelID, "I'm shutting down, now. Bye! 👋") await data.sender.send(data.updateChannelID, "I'm shutting down, now. Bye! 👋")

View File

@@ -21,7 +21,7 @@
"author": "Naaturel", "author": "Naaturel",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"canvas": "^3.2.0", "@napi-rs/canvas": "^0.1.82",
"discord.js": "^14.22.1", "discord.js": "^14.22.1",
"dotenv": "^16.0.3", "dotenv": "^16.0.3",
"express": "^4.21.2", "express": "^4.21.2",

View File

@@ -1,21 +1,55 @@
import {NameCardCreator} from "../wwwroot/core/namecards/nameCardCreator.js";
import {launchWorker} from "../wwwroot/core/namecards/workerLauncher.js";
import {data} from "../wwwroot/core/appData.js"; import {data} from "../wwwroot/core/appData.js";
import {launchWorker} from "../wwwroot/core/namecards/workerLauncher.js";
import {AttachmentBuilder} from "discord.js";
import {Logger} from "../wwwroot/core/logging/logger.js";
import StringFormatter from "../wwwroot/core/utils/stringFormatter.js";
const templatePath = "./wwwroot/assets/name-card-template.png"; data.client.on('clientReady', async () => {
const avatarPath = "./tests/assets/avatar-test.png"; console.log("Ready!");
const name = "Aude Vaiselle";
const guild = await data.client.guilds.fetch(data.testGuildID);
const member = await guild.members.fetch(data.testUserID);
console.log("Emitting fake guildMemberAdd...");
data.client.emit("guildMemberAdd", member);
});
data.client.on('guildMemberAdd', async (member) => {
const possibleMessages = [
"<@:user> is one of us!",
"I know what you are, <@:user>...",
"Osmanthus wine tastes the same as I— oop, wrong line <@:user>",
"Yeah yeah, welcome or whatever <@:user>",
"OH. MY. GOD Y'ALL— <@:user> is here!",
"So... we're all seeing <@:user, right?>",
"<@:user> is right behind me, aren't they...?"
]
const choseMessage = possibleMessages[Math.floor(Math.random() * possibleMessages.length)];
try { try {
launchWorker({ const avatarUrl = member.user.displayAvatarURL({ extension: 'png', size: 512 });
const username = member.displayName || member.user.username;
const result = await launchWorker({
templatePath: data.nameCardTemplate, templatePath: data.nameCardTemplate,
avatarURL: avatarPath, avatarURL: avatarUrl,
username: name, username: username,
}).then(buffer => { });
//Send name card here...
console.log('Name card sent!'); const attachment = new AttachmentBuilder(Buffer.from(result.result), { name: 'namecard.png' });
}).catch(console.error);
const channel = await member.guild.channels.fetch(data.welcomeChannelID);
await channel.send({
content: StringFormatter.format(choseMessage, [ {key : "user", value : member.id} ]),
allowedMentions: {
users: [member.id]
},
files: [attachment]
});
} catch (err) { } catch (err) {
console.error('Failed to generate/send name card:', err); await Logger.error('Failed to generate/send name card:', err);
} }
});
await data.client.login(process.env.DISCORD_TOKEN);

View File

@@ -24,6 +24,9 @@ const updateChannelID = process.env.BOT_UPDATE_CHANNEL_ID;
const socialChannelID = process.env.SOCIAL_CHANNEL_ID const socialChannelID = process.env.SOCIAL_CHANNEL_ID
const welcomeChannelID = process.env.WELCOME_CHANNEL_ID const welcomeChannelID = process.env.WELCOME_CHANNEL_ID
const testGuildID = process.env.TEST_GUILD_ID;
const testUserID = process.env.TEST_USER_ID;
const filePath = ".instagram_client_tokens.json"; const filePath = ".instagram_client_tokens.json";
const usersToken = new UsersToken(filePath) const usersToken = new UsersToken(filePath)
@@ -41,6 +44,8 @@ export const data = {
updateChannelID, updateChannelID,
socialChannelID, socialChannelID,
welcomeChannelID, welcomeChannelID,
testGuildID,
testUserID,
instagramTokenManager, instagramTokenManager,
nameCardTemplate nameCardTemplate
//tiktokTokenManager //tiktokTokenManager

View File

@@ -1,19 +1,16 @@
import fs from "fs"; import {createCanvas, GlobalFonts, loadImage} from "@napi-rs/canvas";
import path from "path"; import path from "path";
import { createCanvas, loadImage, registerFont } from "canvas"; import { fileURLToPath } from "url";
export class NameCardCreator { export class NameCardCreator {
constructor(templatePath) { constructor(templatePath) {
this.templatePath = templatePath; this.templatePath = templatePath;
this.loadFont("./wwwroot/assets/fonts/Fredoka/static/Fredoka-Bold.ttf"); const __dirname = path.dirname(fileURLToPath(import.meta.url));
} const fullPath = path.join(__dirname, "../../assets/fonts/Fredoka/static/Fredoka-Bold.ttf");
GlobalFonts.registerFromPath(
loadFont(fontPath) { fullPath,
const fullPath = path.resolve(fontPath); "Fredoka Bold"
if (!fs.existsSync(fullPath)) { );
throw new Error(`Font file not found at ${fullPath}`);
}
registerFont(fullPath, { family: "Fredoka Bold" });
} }
/** /**
@@ -85,7 +82,7 @@ export class NameCardCreator {
smallCtx = smallCanvas.getContext("2d"); smallCtx = smallCanvas.getContext("2d");
smallCtx.drawImage(canvas, 0, 0, 1500, 500); smallCtx.drawImage(canvas, 0, 0, 1500, 500);
return smallCanvas.toBuffer(); return smallCanvas.toBuffer("image/png");
} catch (err) { } catch (err) {
console.error("Error creating name card:", err); console.error("Error creating name card:", err);
throw err; throw err;

View File

@@ -8,9 +8,11 @@ parentPort.on("message", async (data) => {
const creator = new NameCardCreator(templatePath); const creator = new NameCardCreator(templatePath);
const buffer = await creator.getWelcomeCard(avatarURL, username); const buffer = await creator.getWelcomeCard(avatarURL, username);
parentPort.postMessage({ result: buffer }, [buffer.buffer]); parentPort.postMessage({ result: buffer });
} catch (err) { } catch (err) {
parentPort.postMessage({ error: err.message }); parentPort.postMessage({ error: err.message });
} finally {
parentPort.close();
} }
}); });

View File

@@ -21,7 +21,6 @@ function launchWorker({ templatePath, avatarURL, username }) {
worker.postMessage({ templatePath, avatarURL, username }); worker.postMessage({ templatePath, avatarURL, username });
worker.once('message', async (result) => { worker.once('message', async (result) => {
console.log("worker terminated");
resolve(result); resolve(result);
}); });