diff --git a/Dockerfile b/Dockerfile index e7cf1cc8..4582aa6d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,8 +3,6 @@ FROM node:21-slim as dependency-base RUN apt-get update -yqq \ && apt-get install -yqq \ python3 build-essential pkg-config \ - # https://github.com/Automattic/node-canvas/issues/1065#issuecomment-654706161 - libpixman-1-dev libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev \ && apt-get clean -yqqq FROM dependency-base as build @@ -31,7 +29,6 @@ FROM node:21-slim fonts-noto-color-emoji \ fontconfig \ fonts-liberation \ - libpixman-1-dev libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev \ && apt-get clean -yqqq \ && fc-cache -f -v diff --git a/package-lock.json b/package-lock.json index b4cb9afc..40d73ced 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,8 +10,8 @@ "license": "MIT", "dependencies": { "@discordjs/voice": "^0.16.1", + "@napi-rs/canvas": "^0.1.44", "@resvg/resvg-js": "^2.6.0", - "canvas": "^2.11.2", "chrono-node": "^2.7.4", "croner": "^8.0.0", "discord.js": "^14.14.1", @@ -442,6 +442,164 @@ "node-pre-gyp": "bin/node-pre-gyp" } }, + "node_modules/@napi-rs/canvas": { + "version": "0.1.44", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.44.tgz", + "integrity": "sha512-IyhSndjw29LR1WqkUZvTJI4j8Ve1QGbZYtpdQjJjcFvsvJS4/WHzOWV8ZciLPJBhrYvSQf/JbZJy5LHmFV+plg==", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@napi-rs/canvas-android-arm64": "0.1.44", + "@napi-rs/canvas-darwin-arm64": "0.1.44", + "@napi-rs/canvas-darwin-x64": "0.1.44", + "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.44", + "@napi-rs/canvas-linux-arm64-gnu": "0.1.44", + "@napi-rs/canvas-linux-arm64-musl": "0.1.44", + "@napi-rs/canvas-linux-x64-gnu": "0.1.44", + "@napi-rs/canvas-linux-x64-musl": "0.1.44", + "@napi-rs/canvas-win32-x64-msvc": "0.1.44" + } + }, + "node_modules/@napi-rs/canvas-android-arm64": { + "version": "0.1.44", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.44.tgz", + "integrity": "sha512-3UDlVf1CnibdUcM0+0xPH4L4/d/tCI895or0y7mr/Xlaa1tDmvcQCvBYl9G54IpXsm+e4T1XkVrGGJD4k1NfSg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-darwin-arm64": { + "version": "0.1.44", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.44.tgz", + "integrity": "sha512-Y1Yx0H45Iicx2b6pcrlICjlwgylLtqi0t5OJgeUXnxLcJ1+aEpmjLr16tddqHkmGUw/nBRAwfPJrf3GaOwWowQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-darwin-x64": { + "version": "0.1.44", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.44.tgz", + "integrity": "sha512-gbzeNz13DFH0Ak5ENyQ5ZEuSuCjNDxA/OV9P5f19lywbOVL5Ol+qgKX0BXBcP3O3IXWahruOvmmLUBn9h1MHpA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { + "version": "0.1.44", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.44.tgz", + "integrity": "sha512-Sad3/eGyzTZiyJFeFrmX1M3aRp0n3qTAXeCm6EeAjCFGk8TWd4cINCGT3IRY4wmCvNnpe6C4fM03K07cU5YYwA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-gnu": { + "version": "0.1.44", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.44.tgz", + "integrity": "sha512-bCrI9naYGPRFHePMGN+wlrWzC+Swi6uc1YzFg4/wOYzHKSte8FXHrGspHOPPr12BCEmgg3yXK8nnLjxGdlAWtg==", + "cpu": [ + "arm64" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-musl": { + "version": "0.1.44", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.44.tgz", + "integrity": "sha512-gB/ao9zBQaOJik4arOKJisZaG+v7DuyBW7UdG+0L80msAuJTTH2UgWOnmXfZwPxzxNbFKzOa8r48uVzfTaAHGQ==", + "cpu": [ + "arm64" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-gnu": { + "version": "0.1.44", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.44.tgz", + "integrity": "sha512-pvHy1bJ0DDD4Bsx6yuFnqpIyBW7+2iIK5BpvmL36zXE+7w2MEeaYzLUWTBhrXj8rzHys6MwLmHNlkw65R80YbQ==", + "cpu": [ + "x64" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-musl": { + "version": "0.1.44", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.44.tgz", + "integrity": "sha512-5QaeYqNZ/u1QI2E/UqvnmuORT6cI1qTtLosPp/y4awaK+/LXQEzotHNv0nan0z4EV/0mXsJswY9JpISRJzx+Kw==", + "cpu": [ + "x64" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-win32-x64-msvc": { + "version": "0.1.44", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.44.tgz", + "integrity": "sha512-pbeTGLox+I+sMVl/FFO21Xvp0PhijsuEr9gaynmN2X7FPTg+CCuuBDhfSU5iMAtcCCYFCk8ridZIWy5jkcf72w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@npmcli/fs": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", @@ -1016,6 +1174,8 @@ "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", "hasInstallScript": true, + "optional": true, + "peer": true, "dependencies": { "@mapbox/node-pre-gyp": "^1.0.0", "nan": "^2.17.0", @@ -1282,6 +1442,8 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "optional": true, + "peer": true, "dependencies": { "mimic-response": "^2.0.0" }, @@ -2021,6 +2183,8 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "optional": true, + "peer": true, "engines": { "node": ">=8" }, @@ -2162,7 +2326,9 @@ "node_modules/nan": { "version": "2.17.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", - "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", + "optional": true, + "peer": true }, "node_modules/negotiator": { "version": "0.6.3", @@ -2952,12 +3118,16 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "optional": true, + "peer": true }, "node_modules/simple-get": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "optional": true, + "peer": true, "dependencies": { "decompress-response": "^4.2.0", "once": "^1.3.1", diff --git a/package.json b/package.json index 3d61b31a..8d6477f1 100644 --- a/package.json +++ b/package.json @@ -27,8 +27,8 @@ "homepage": "https://github.com/NullDev/CSZ-Bot#readme", "dependencies": { "@discordjs/voice": "^0.16.1", + "@napi-rs/canvas": "^0.1.44", "@resvg/resvg-js": "^2.6.0", - "canvas": "^2.11.2", "chrono-node": "^2.7.4", "croner": "^8.0.0", "discord.js": "^14.14.1", diff --git a/src/commands/bonk.ts b/src/commands/bonk.ts index 65480ea1..3a491a25 100644 --- a/src/commands/bonk.ts +++ b/src/commands/bonk.ts @@ -1,6 +1,6 @@ import * as fs from "node:fs/promises"; -import nodeCanvas from "canvas"; +import { createCanvas, loadImage } from "@napi-rs/canvas"; import type { Client, GuildMember } from "discord.js"; import type { CommandResult, MessageCommand } from "./command.js"; @@ -10,8 +10,6 @@ import { getConfig } from "../utils/configHandler.js"; const config = getConfig(); -const { createCanvas, loadImage } = nodeCanvas; - const createBonkMeme = async (author: GuildMember): Promise => { const bonk = await fs.readFile("assets/bonk.png"); const bonkImage = await loadImage(bonk); @@ -25,7 +23,7 @@ const createBonkMeme = async (author: GuildMember): Promise => { ctx.drawImage(avatarImage, 120, 90); ctx.drawImage(bonkImage, 0, 0); - return canvas.toBuffer(); + return await canvas.encode("png"); }; export class BonkCommand implements MessageCommand { diff --git a/src/commands/special/where.ts b/src/commands/special/where.ts index f437d192..4e3ecf73 100644 --- a/src/commands/special/where.ts +++ b/src/commands/special/where.ts @@ -1,17 +1,14 @@ import { Message, Client, cleanContent } from "discord.js"; -import nodeCanvas from "canvas"; +import { createCanvas, loadImage, GlobalFonts } from "@napi-rs/canvas"; +import { readFile } from "fs/promises"; import type { SpecialCommand } from "../command.js"; import { countWords, substringAfter } from "../../utils/stringUtils.js"; -const { createCanvas, loadImage, registerFont } = nodeCanvas; - if (process.env.NODE_ENV === "production") { // This is a simple detection if we're running inside docker // We assume that every developer that wants to use this feature has impact installed - registerFont("assets/impact.ttf", { - family: "Impact", - }); + GlobalFonts.register(await readFile("assets/impact.ttf"), "Impact"); } export class WhereCommand implements SpecialCommand { @@ -70,6 +67,6 @@ export class WhereCommand implements SpecialCommand { ctx.fillStyle = "#fff"; ctx.fillText(text, textPos.x, textPos.y); - return canvas.toBuffer(); + return await canvas.encode("png"); } } diff --git a/src/commands/stempelkarte.ts b/src/commands/stempelkarte.ts index ad6d2055..097d98c5 100644 --- a/src/commands/stempelkarte.ts +++ b/src/commands/stempelkarte.ts @@ -1,5 +1,5 @@ import * as fs from "node:fs/promises"; -import nodeCanvas from "canvas"; +import { createCanvas, loadImage } from "@napi-rs/canvas"; import { ImageSize, Client, @@ -15,8 +15,6 @@ import log from "../utils/logger.js"; import type { ApplicationCommand, CommandResult } from "./command.js"; import { chunkArray } from "../utils/arrayUtils.js"; -const { createCanvas, loadImage } = nodeCanvas; - const stempelLocations = [ // 1-3 { x: 214, y: 38 }, @@ -106,7 +104,7 @@ const drawStempelkarteBackside = async ( firmenstempelCenter.y - subjectAvatar.height / 2, ); - return canvas.toBuffer(); + return await canvas.encode("png"); }; export class StempelkarteCommand implements ApplicationCommand {