peechu
Version:
Peechu Music Card.
129 lines (108 loc) • 6.03 kB
JavaScript
const canvas = require("@napi-rs/canvas");
const path = require('path');
const { colorFetch } = require("../functions/colorFetch");
canvas.GlobalFonts.registerFromPath(path.join(__dirname, '../node_modules/peechu/build/structures/font/circularstd-black.otf'), "circular-std");
canvas.GlobalFonts.registerFromPath(path.join(__dirname, '../node_modules/peechu/build/structures/font/notosans-jp-black.ttf'), "noto-sans-jp");
canvas.GlobalFonts.registerFromPath(path.join(__dirname, '../node_modules/peechu/build/structures/font/notosans-black.ttf'), "noto-sans");
canvas.GlobalFonts.registerFromPath(path.join(__dirname, '../node_modules/peechu/build/structures/font/notoemoji-bold.ttf'), "noto-emoji");
canvas.GlobalFonts.registerFromPath(path.join(__dirname, '../node_modules/peechu/build/structures/font/notosans-kr-black.ttf'), "noto-sans-kr");
canvas.GlobalFonts.registerFromPath(path.join(__dirname, '../node_modules/musicard-bun/build/structures/font/Chewy-Regular.ttf'), "chewy");
canvas.GlobalFonts.registerFromPath(path.join(__dirname, '../node_modules/musicard-bun/build/structures/font/Space.ttf'), "space");
const DEFAULT_THUMBNAIL = path.join(__dirname, '../assets/no_thumbnail.png');
const BACKGROUND_IMAGES_DIR = path.join(__dirname, '../assets/backgrounds');
const BACKGROUND_FILES = [
'1.png',
'2.png',
'3.png',
'4.png',
'5.png',
'6.png',
'7.png',
'8.png',
'9.png',
'10.png',
'11.png',
'12.png',
'13.png',
'14.png',
'15.png',
'16.png',
'17.png',
'18.png',
'19.png',
'20.png',
'21.png',
];
const ALLOWED_COLORS = ['#ebb866', '#ffc3bf', '#fcfcfc'];
class peechu {
constructor(options) {
this.name = options?.name ?? null;
this.author = options?.author ?? null;
this.color = options?.color ?? null;
this.theme = options?.theme ?? 'peechu';
this.brightness = options?.brightness ?? 0;
this.thumbnail = options?.thumbnail ?? DEFAULT_THUMBNAIL;
this.progress = options?.progress ?? 0;
this.starttime = options?.startTime ?? '0:00';
this.endtime = options?.endTime ?? '0:00';
this.requester = options?.requester ?? null;
}
setName(name) { this.name = name; return this; }
setAuthor(author) { this.author = author; return this; }
setColor(color) { this.color = color; return this; }
setTheme(theme) { this.theme = theme || 'peechu'; return this; }
setBrightness(brightness) { this.brightness = brightness; return this; }
setThumbnail(thumbnail) { this.thumbnail = thumbnail; return this; }
setProgress(progress) { this.progress = progress; return this; }
setStartTime(starttime) { this.starttime = starttime; return this; }
setEndTime(endtime) { this.endtime = endtime; return this; }
setRequester(requester) { this.requester = `${requester}`; return this; }
async build() {
if (!this.color) this.setColor('ff0000');
let validatedProgress = parseFloat(this.progress);
if (Number.isNaN(validatedProgress) || validatedProgress < 0 || validatedProgress > 100)
throw new Error('Invalid progress parameter, must be between 0 to 100');
validatedProgress = Math.max(2, Math.min(validatedProgress, 99));
const validatedColor = await colorFetch(this.color, parseInt(this.brightness), this.thumbnail);
this.name = this.name?.length > 15 ? `${this.name.slice(0, 15)}...` : this.name;
this.author = this.author?.length > 15 ? `${this.author.slice(0, 15)}` : this.author;
this.requester = this.requester?.length > 12 ? `${this.requester.slice(0, 10)}...` : this.requester;
if (this.theme === 'peechu') {
const frame = canvas.createCanvas(800, 200);
const ctx = frame.getContext("2d");
const backgroundFile = BACKGROUND_FILES[Math.floor(Math.random() * BACKGROUND_FILES.length)];
const backgroundPath = path.join(BACKGROUND_IMAGES_DIR, backgroundFile);
const background = await canvas.loadImage(backgroundPath);
ctx.drawImage(background, 0, 0, frame.width, frame.height);
const thumbnailCanvas = canvas.createCanvas(800, 200);
const thumbnailCtx = thumbnailCanvas.getContext('2d');
let thumbnailImage;
try {
thumbnailImage = await canvas.loadImage(this.thumbnail);
} catch {
thumbnailImage = await canvas.loadImage(DEFAULT_THUMBNAIL);
}
const thumbnailSize = Math.min(thumbnailImage.width, thumbnailImage.height);
thumbnailCtx.drawImage(thumbnailImage, (thumbnailImage.width - thumbnailSize) / 2,
(thumbnailImage.height - thumbnailSize) / 2, thumbnailSize, thumbnailSize, 0, 0, thumbnailCanvas.width, thumbnailCanvas.height);
ctx.drawImage(thumbnailCanvas, 50, 40, 180, 130);
ctx.strokeStyle = '#CF9FFF';
ctx.lineWidth = 5;
ctx.strokeRect(50, 40, 180, 130);
const randomColor = () => ALLOWED_COLORS[Math.floor(Math.random() * ALLOWED_COLORS.length)];
ctx.font = "bold 38px circular-std, noto-emoji, noto-sans-jp, noto-sans, noto-sans-kr";
ctx.fillStyle = randomColor();
ctx.fillText(this.name, 250, 100);
ctx.font = "bold 22px circular-std, noto-emoji, noto-sans-jp, noto-sans, noto-sans-kr";
ctx.fillStyle = randomColor();
const authorTextWidth = ctx.measureText(this.author).width;
ctx.fillText(this.author, 250, 140);
ctx.fillStyle = randomColor();
ctx.fillText(this.requester, 250 + authorTextWidth + 10, 140);
return frame.toBuffer("image/png");
} else {
throw new Error('Invalid theme parameter, must be "peechu"');
}
}
}
module.exports = { peechu };