UNPKG

canvafy

Version:

Make configurable canvas easily with Canvafy

343 lines (293 loc) 10.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const { createCanvas, loadImage, GlobalFonts } = require('@napi-rs/canvas'); const Util = require("../plugins/Util"); const path = require('path'); /** * @typedef {object} Spotify * @see {Spotify} * @example const spotifyCard = await new canvafy.Spotify() * @type {Class} */ module.exports = class newSpotify { constructor(options) { this.font = { name: options?.font?.name ?? "Manrope", path: options?.font?.path }; this.album = null; this.artist = null; this.border = null; this._bar_width = 1400; this.end = null; this.overlay_opacity = null; this.image = null; this.blur = 3; this.title = null; this.start = null; this.spotifyLogo = true; this.randomColors = ["#0c0c0c","#121212","#282828","#1c1c1c","#244c66"]; } /** * .setAlbum * @param {string} name Album Name * @returns {Spotify} * @example setAlbum("Alan Walker Album") */ setAlbum(name) { if (!name || typeof name !== "string") throw new Error("The argument of the setAlbum method must be a string."); this.album = name; return this; } /** * .setAuthor * @param {string} name Artist Name * @returns {Spotify} * @example setAuthor("Alan Walker, Ava Max") */ setAuthor(name) { if (!name || typeof name !== "string") throw new Error("The argument of the setAuthor method must be a string."); this.artist = name; return this; } /** * .setBorder * @param {string} color "hexcolor" * @returns {Spotify} * @example setBorder("#fff") */ setBorder(color) { if (color) { if (/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/.test(color)) { this.border = color; return this; } else { throw new Error("Invalid color for the argument in the setBorder method. You must give a hexadecimal color.") } } else { throw new Error("You must give a hexadecimal color as the argument of setBorder method."); } } /** * .setOverlayOpacity * @param {number} opacity must be between 0 and 1 * @returns {Spotify} * @example setOverlayOpacity(0.7) */ setOverlayOpacity(opacity = 0) { if (opacity) { if (opacity >= 0 && opacity <= 1) { this.overlay_opacity = opacity; return this; } else { throw new Error("The value of the opacity of setOverlayOpacity method must be between 0 and 1 (0 and 1 included)."); } } } /** * .setBlur * @param {number} blur setImage blur effect px * @default blur 3 * @returns {Spotify} * @example setBlur(5) - Max 15px */ setBlur(blur = 3) { if (blur) { if (blur >= 0 && blur <= 15) { this.blur = blur; return this; } else { throw new Error("The value of the opacity of setBlur method must be between 0 and 15 (0 and 15 included)."); } } } /** * .setImage * @param {string|Buffer|Image} image Album Or Song Image * @returns {Spotify} * @example setImage("https://someone-image.png") */ setImage(image) { if (!image) throw new Error("The argument of the setImage method must be a string or a Buffer or a Canvas.Image."); this.image = image; return this; } /** * .setTitle * @param {string} title Title To Set * @returns {Spotify} * @example setTitle("Alone, Pt II") */ setTitle(title) { if (!title || typeof title !== "string") throw new Error("The argument of the setTitle method must be a string."); this.title = title; return this; } /** * .setSpotifyLogo * @param {boolean} bool must be "true" or "false" * @returns {Spotify} * @default bool true * @example setSpotifyLogo(true) */ setSpotifyLogo(bool){ if(typeof bool !== "boolean") { throw new Error("You must give a abbreviate number true or false argument."); } this.spotifyLogo = bool; return this; } /** * .setTimestamp * @param {number} start Start Timestamp * @param {number} end End Timestamp * @returns {Spotify} * @example setTimestamp(40000,179000) */ setTimestamp(start, end) { if (!start || typeof start !== "number") throw new Error("The first argument of the setTimestamp method must be a number."); if (!end || typeof end !== "number") throw new Error("The first argument of the setTimestamp method must be a number."); this.start = start; this.end = end; return this; } /** * @private */ _calcule_progress(current, total) { const progress = (current / total) * this._bar_width; if (isNaN(progress) || current < 0) { return 0; } else if (progress > this._bar_width) { return this._bar_width; } else { return progress; } } async build() { if (!this.title) throw new Error("Missing 'title' parameter."); if (!this.artist) throw new Error("Missing 'artist' parameter."); if (!this.start) throw new Error("Missing 'start' parameter."); if (!this.end) throw new Error("Missing 'end' parameter."); if (this.font.path) GlobalFonts.registerFromPath(this.font.path, this.font.name); const start_format = Util.format_time(this.start > this.end ? this.end : this.start); const end_format = Util.format_time(this.end); const canvas = createCanvas(2000, 585); const ctx = canvas.getContext("2d"); if (this.border) { ctx.beginPath(); ctx.lineWidth = 8; ctx.strokeStyle = this.border; ctx.moveTo(55, 15); ctx.lineTo(canvas.width - 55, 15); ctx.quadraticCurveTo(canvas.width - 20, 20, canvas.width - 15, 55); ctx.lineTo(canvas.width - 15, canvas.height - 55); ctx.quadraticCurveTo(canvas.width - 20, canvas.height - 20, canvas.width - 55, canvas.height - 15); ctx.lineTo(55, canvas.height - 15); ctx.quadraticCurveTo(20, canvas.height - 20, 15, canvas.height - 55); ctx.lineTo(15, 55); ctx.quadraticCurveTo(20, 20, 55, 15); ctx.lineTo(56, 15); ctx.stroke(); ctx.closePath(); } ctx.beginPath(); ctx.moveTo(65, 25); ctx.lineTo(canvas.width - 65, 25); ctx.quadraticCurveTo(canvas.width - 25, 25, canvas.width - 25, 65); ctx.lineTo(canvas.width - 25, canvas.height - 65); ctx.quadraticCurveTo(canvas.width - 25, canvas.height - 25, canvas.width - 65, canvas.height - 25); ctx.lineTo(65, canvas.height - 25); ctx.quadraticCurveTo(25, canvas.height - 25, 25, canvas.height - 65); ctx.lineTo(25, 65); ctx.quadraticCurveTo(25, 25, 65, 25); ctx.lineTo(66, 25); ctx.closePath(); ctx.clip(); ctx.globalAlpha = 1; if (!this.image || this.image == null) { ctx.beginPath(); ctx.fillStyle = `${this.randomColors[Math.floor(Math.random()*this.randomColors.length)]}`; ctx.fillRect(10, 10, canvas.width, canvas.height) } else if (this.image) { try { ctx.filter = `blur(${this.blur}px)`; ctx.drawImage(await loadImage(this.image), 0, -500, canvas.width, 2000); } catch { throw new Error("The image given in the parameter of the setImage method is not valid or you are not connected to the internet."); } } ctx.filter = "none"; if(this.overlay_opacity){ ctx.beginPath(); ctx.globalAlpha = this.overlay_opacity; ctx.fillStyle = "#000"; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.save(); } ctx.globalAlpha = 1; const progressBar = (ctx, x, y, width, height) => { ctx.fillStyle = "#6a625e"; roundRect(ctx, x, y, width, height, 8, true, false); ctx.fillStyle = "#fff"; roundRect(ctx, x, y, this._calcule_progress(this.start, this.end), height, 8, true, false); ctx.beginPath(); ctx.arc(x + this._calcule_progress(this.start, this.end), y + height / 2, height * 1.25, 0, 360); ctx.fill(); ctx.closePath(); }; progressBar(ctx, 300, 400, this._bar_width, 8) if(this.spotifyLogo){ try { ctx.drawImage(await loadImage(`${__dirname}/../assets/images/spotify-logo.png`), 950, 60, 100, 100); } catch { throw new Error("The image given in the parameter of the Spotify method is not valid or you are not connected to the internet."); } } ctx.fillStyle = "#fff"; ctx.font = `bold 50px ${this.font.name}`; ctx.textAlign = "center"; ctx.fillText(this.title.length >= 40 ? this.title.slice(0, 40)+"...": this.title, 1000, 285); ctx.fillStyle = "#94a3b8"; ctx.font = `bold 28px ${this.font.name}`; ctx.textAlign = "center"; ctx.fillText(`${this.artist.length >= 40 ? this.artist.slice(0, 40)+"...":this.artist}`, 1000, 215); if (this.album && typeof this.album === "string") { ctx.fillStyle = "#94a3b8"; ctx.font = `regular 30px ${this.font.name}`; ctx.fillText(`${this.album.length >= 40 ? this.album.slice(0, 40)+"...":this.album}`, 1000, 350); } ctx.fillStyle = "#cbd5e1"; ctx.font = `"regular 20px ${this.font.name}` ctx.fillText(end_format, 1782, 412); ctx.fillStyle = "#cbd5e1"; ctx.font = `regular 20px ${this.font.name}`; ctx.fillText(start_format, 230, 412); return canvas.toBuffer('image/png'); } } function roundRect(ctx, x, y, width, height, radius = 5, fill = true, stroke = false) { if (typeof radius === "number") { radius = { tl: radius, tr: radius, br: radius, bl: radius }; } else { let defaultRadius = { tl: 0, tr: 0, br: 0, bl: 0 }; for (let side in defaultRadius) { radius[side] = radius[side] || defaultRadius[side]; } } ctx.beginPath(); ctx.moveTo(x + radius.tl, y); ctx.lineTo(x + width - radius.tr, y); ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr); ctx.lineTo(x + width, y + height - radius.br); ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height); ctx.lineTo(x + radius.bl, y + height); ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl); ctx.lineTo(x, y + radius.tl); ctx.quadraticCurveTo(x, y, x + radius.tl, y); ctx.closePath(); if (fill) { ctx.fill(); } if (stroke) { ctx.stroke(); } };