diff --git a/README.md b/README.md
index 6e78a54..20cf7fd 100644
--- a/README.md
+++ b/README.md
@@ -18,21 +18,42 @@ npm install songcard
# or
yarn add songcard
```
+
+
+## Usage
+
+| Option | Type | Description |
+|------------------------|------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
+| imageBg | String | Image that will be display to the songcard.
Example: https://images-ext-1.discordapp.net/external/uw_-bWFyeXnWb11wGThe2CAbTYdrxzFqMJ2trxDIYVE/https/i.scdn.co/image/ab67616d0000b2738ad8f5243d6534e03b656c8b?width=468&height=468
File format: PNG/JPEG |
+| imageText | String | Text that will be display to the songcard. |
+| trackStream | Boolean | Whether to set the trackDuration and trackTotalDuration to `LIVE`
Example: if trackStream is `true` the trackDuration and totalTrackDuration will show as `LIVE` else it will show number. |
+| trackDuration | Integer | Show current duration of the songs. If no value provide it will show `0:00`. |
+| trackTotalDuration | Integer | Show the songs duration. |
+
+
+
+# Themes
+
+## 1. Classic
+
+
+![](https://cdn.discordapp.com/attachments/959777491818528788/1215117638498258994/card.png?ex=65fb957c&is=65e9207c&hm=c9ac7d6611677d0279395a0da55a34efd6b29addd245577b4a0d47cbbabbc6cd&)
+
+### Example
-## Example
```js
-const createCard = require("songcard"); // Import
+const { classicCard } = require("songcard");
const { AttachmentBuilder } = require("discord.js");
client.on("interactionCreate", async (message) => {
- const cardImage = await createCard(
- imageBg = "https://images-ext-1.discordapp.net/external/uw_-bWFyeXnWb11wGThe2CAbTYdrxzFqMJ2trxDIYVE/https/i.scdn.co/image/ab67616d0000b2738ad8f5243d6534e03b656c8b?width=468&height=468",
- imageText = "Die For You (with Ariana Grande) - Remix",
- trackStream = false,
- trackDuration = 220000,
- trackTotalDuration = 233000,
- );
+ const cardImage = await classicCard({
+ imageBg: "https://images-ext-1.discordapp.net/external/uw_-bWFyeXnWb11wGThe2CAbTYdrxzFqMJ2trxDIYVE/https/i.scdn.co/image/ab67616d0000b2738ad8f5243d6534e03b656c8b?width=468&height=468",
+ imageText: "Die For You (with Ariana Grande) - Remix",
+ trackStream: false,
+ trackDuration: 220000,
+ trackTotalDuration: 233000,
+ });
const attachment = new AttachmentBuilder(cardImage, {
name: "card.png",
@@ -45,25 +66,36 @@ client.on("interactionCreate", async (message) => {
client.login("token");
```
+
-## Usage
+## 2. Simple
-| Option | Type | Description |
-|------------------------|------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
-| imageBg | String | Image that will be display to the songcard.
Example: https://images-ext-1.discordapp.net/external/uw_-bWFyeXnWb11wGThe2CAbTYdrxzFqMJ2trxDIYVE/https/i.scdn.co/image/ab67616d0000b2738ad8f5243d6534e03b656c8b?width=468&height=468
File format: PNG/JPEG |
-| imageText | String | Text that will be display to the songcard. |
-| trackStream | Boolean | Whether to set the trackDuration and trackTotalDuration to `LIVE`
Example: if trackStream is `true` the trackDuration and totalTrackDuration will show as `LIVE` else it will show number. |
-| trackDuration | Integer | Show current duration of the songs. If no value provide it will show `0:00`. |
-| trackTotalDuration | Integer | Show the songs duration. |
+![](https://media.discordapp.net/attachments/959777491818528788/1215115258000183396/card.png?ex=65fb9345&is=65e91e45&hm=6b67d2ccbe049a6d6d859607f3d948635ea7f10bb6e5e35316c4e02697ee52be&=&format=webp&quality=lossless&width=300&height=300)
-
-
+### Example
-![](https://cdn.discordapp.com/attachments/897715616155328542/1146301148706390036/image.png)
+```js
+const { simpleCard } = require("songcard");
+const { AttachmentBuilder } = require("discord.js");
-
+client.on("interactionCreate", async (message) => {
+
+ const cardImage = await simpleCard({
+ imageBg:
+ "https://i.scdn.co/image/ab67616d0000b27328862817fc34472677afb214",
+ imageText: "Yesterday",
+ });
-![](https://cdn.discordapp.com/attachments/959777491818528788/1146131591131832330/card.png)
+ const attachment = new AttachmentBuilder(cardImage, {
+ name: "card.png",
+ });
+ interaction.channel.send({
+ files: [attachment],
+ });
+});
+
+client.login("token");
+```
diff --git a/src/index.js b/src/index.js
index 9f4e108..ce56164 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,197 +1,4 @@
-const { createCanvas, loadImage } = require("canvas");
-const Jimp = require("jimp");
+const { classicCard } = require("./themes/classicCard");
+const { simpleCard } = require("./themes/simpleCard");
-async function createCard(
- imageBg,
- imageText,
- trackStream,
- trackDuration,
- trackTotalDuration
-) {
- const prettyMilliseconds = (await import("pretty-ms")).default;
- const canvasWidth = 1200;
- const canvasHeight = 400;
- const canvas = createCanvas(canvasWidth, canvasHeight);
- const ctx = canvas.getContext("2d");
-
- const imageToAdd = await loadImage(imageBg);
- const imageToAdds = await Jimp.read(imageBg);
-
- const sampleColor = imageToAdds.getPixelColor(0, 0);
- const { r, g, b } = Jimp.intToRGBA(sampleColor);
-
- const brightnessFactor = 0.7;
-
- const adjustedR = Math.round(r * brightnessFactor);
- const adjustedG = Math.round(g * brightnessFactor);
- const adjustedB = Math.round(b * brightnessFactor);
-
- const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
- gradient.addColorStop(0, `rgb(${adjustedR}, ${adjustedG}, ${adjustedB})`);
- gradient.addColorStop(1, `rgb(${adjustedR}, ${adjustedG}, ${adjustedB})`);
-
- ctx.fillStyle = gradient;
- ctx.fillRect(0, 0, canvas.width, canvas.height);
-
- const totalTrackDuration = trackTotalDuration;
- const currentTrackDuration = trackDuration;
-
- const progressWidth = 700;
- const progressHeight = 8;
- const progressX = 420;
- const progressY = 280;
- const borderRadius1 = 10;
-
- const progressPercentage = (currentTrackDuration / totalTrackDuration) * 100;
-
- const gradients = ctx.createLinearGradient(
- progressX,
- 0,
- progressX + progressWidth,
- 0
- );
-
- gradients.addColorStop(0, "white");
-
- gradients.addColorStop(progressPercentage / 100, "white");
- gradients.addColorStop(progressPercentage / 100, "gray");
- gradients.addColorStop(1, "gray");
-
- ctx.fillStyle = gradients;
-
- ctx.roundRect(
- progressX,
- progressY,
- progressWidth,
- progressHeight,
- borderRadius1
- );
- ctx.fill();
-
- const dotX = progressX + (progressWidth * progressPercentage) / 100;
- const dotY = progressY + progressHeight / 2;
- const dotRadius = 8;
-
- ctx.fillStyle = "white";
- ctx.beginPath();
- ctx.arc(dotX, dotY, dotRadius, 0, Math.PI * 2);
- ctx.closePath();
- ctx.fill();
-
- let duration;
-
- if (!trackDuration) {
- duration = "0:00";
- }
- if (trackDuration) {
- duration = prettyMilliseconds(trackDuration, {
- colonNotation: true,
- secondsDecimalDigits: 0,
- });
- }
-
- let totalDuration;
-
- if (!trackTotalDuration) {
- totalDuration = "0:00";
- }
- if (trackTotalDuration) {
- totalDuration = prettyMilliseconds(trackTotalDuration, {
- colonNotation: true,
- secondsDecimalDigits: 0,
- });
- }
-
- ctx.fillStyle = "#fff";
- ctx.font = "30px Arial";
- const text1X = 420;
- const text1Y = 330;
- ctx.fillText(trackStream ? `LIVE` : duration, text1X, text1Y);
-
- ctx.fillStyle = "#fff";
- ctx.font = "30px Arial";
- const text2X = 1060;
- const text2Y = 330;
- ctx.fillText(trackStream ? `LIVE` : totalDuration, text2X, text2Y);
-
- const imageSize = Math.min(canvasHeight - 80, canvasWidth - 80);
- const imageX = 40;
- const imageY = 40;
- const borderRadius = 25;
-
- ctx.filter = "blur(5px)";
- ctx.drawImage(
- canvas,
- 0,
- 0,
- canvasWidth,
- canvasHeight,
- 0,
- 0,
- canvasWidth,
- canvasHeight
- );
-
- ctx.save();
- ctx.beginPath();
- ctx.moveTo(imageX + borderRadius, imageY);
- ctx.lineTo(imageX + imageSize - borderRadius, imageY);
- ctx.quadraticCurveTo(
- imageX + imageSize,
- imageY,
- imageX + imageSize,
- imageY + borderRadius
- );
- ctx.lineTo(imageX + imageSize, imageY + imageSize - borderRadius);
- ctx.quadraticCurveTo(
- imageX + imageSize,
- imageY + imageSize,
- imageX + imageSize - borderRadius,
- imageY + imageSize
- );
- ctx.lineTo(imageX + borderRadius, imageY + imageSize);
- ctx.quadraticCurveTo(
- imageX,
- imageY + imageSize,
- imageX,
- imageY + imageSize - borderRadius
- );
- ctx.lineTo(imageX, imageY + borderRadius);
- ctx.quadraticCurveTo(imageX, imageY, imageX + borderRadius, imageY);
- ctx.closePath();
- ctx.clip();
- ctx.drawImage(imageToAdd, imageX, imageY, imageSize, imageSize);
- ctx.restore();
-
- const textX = imageX + imageSize + 60;
- const textY = imageY - -60;
-
- const maxWidth = 540;
- const text = imageText;
-
- const textWidth = ctx.measureText(text).width;
-
- if (textWidth > maxWidth) {
- const ellipsisWidth = ctx.measureText("...").width;
-
- const availableWidth = maxWidth - ellipsisWidth;
-
- let truncatedText = text;
- while (ctx.measureText(truncatedText).width > availableWidth) {
- truncatedText = truncatedText.slice(0, -1);
- }
-
- truncatedText += "...";
-
- ctx.fillStyle = "#fff";
- ctx.font = "40px Arial";
- ctx.fillText(truncatedText, textX, textY);
- } else {
- ctx.fillStyle = "#fff";
- ctx.font = "40px Arial";
- ctx.fillText(text, textX, textY);
- }
- return canvas.toBuffer();
-}
-
-module.exports = createCard;
+module.exports = { classicCard, simpleCard }
\ No newline at end of file
diff --git a/src/themes/classicCard.js b/src/themes/classicCard.js
new file mode 100644
index 0000000..6726c6e
--- /dev/null
+++ b/src/themes/classicCard.js
@@ -0,0 +1,197 @@
+const { createCanvas, loadImage } = require("canvas");
+const Jimp = require("jimp");
+
+async function classicCard({
+ imageBg,
+ imageText,
+ trackStream,
+ trackDuration,
+ trackTotalDuration,
+}) {
+ const prettyMilliseconds = (await import("pretty-ms")).default;
+ const canvasWidth = 1200;
+ const canvasHeight = 400;
+ const canvas = createCanvas(canvasWidth, canvasHeight);
+ const ctx = canvas.getContext("2d");
+
+ const imageToAdd = await loadImage(imageBg);
+ const imageToAdds = await Jimp.read(imageBg);
+
+ const sampleColor = imageToAdds.getPixelColor(0, 0);
+ const { r, g, b } = Jimp.intToRGBA(sampleColor);
+
+ const brightnessFactor = 0.7;
+
+ const adjustedR = Math.round(r * brightnessFactor);
+ const adjustedG = Math.round(g * brightnessFactor);
+ const adjustedB = Math.round(b * brightnessFactor);
+
+ const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
+ gradient.addColorStop(0, `rgb(${adjustedR}, ${adjustedG}, ${adjustedB})`);
+ gradient.addColorStop(1, `rgb(${adjustedR}, ${adjustedG}, ${adjustedB})`);
+
+ ctx.fillStyle = gradient;
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+ const totalTrackDuration = trackTotalDuration;
+ const currentTrackDuration = trackDuration;
+
+ const progressWidth = 700;
+ const progressHeight = 8;
+ const progressX = 420;
+ const progressY = 280;
+ const borderRadius1 = 10;
+
+ const progressPercentage = (currentTrackDuration / totalTrackDuration) * 100;
+
+ const gradients = ctx.createLinearGradient(
+ progressX,
+ 0,
+ progressX + progressWidth,
+ 0
+ );
+
+ gradients.addColorStop(0, "white");
+
+ gradients.addColorStop(progressPercentage / 100, "white");
+ gradients.addColorStop(progressPercentage / 100, "gray");
+ gradients.addColorStop(1, "gray");
+
+ ctx.fillStyle = gradients;
+
+ ctx.roundRect(
+ progressX,
+ progressY,
+ progressWidth,
+ progressHeight,
+ borderRadius1
+ );
+ ctx.fill();
+
+ const dotX = progressX + (progressWidth * progressPercentage) / 100;
+ const dotY = progressY + progressHeight / 2;
+ const dotRadius = 8;
+
+ ctx.fillStyle = "white";
+ ctx.beginPath();
+ ctx.arc(dotX, dotY, dotRadius, 0, Math.PI * 2);
+ ctx.closePath();
+ ctx.fill();
+
+ let duration;
+
+ if (!trackDuration) {
+ duration = "0:00";
+ }
+ if (trackDuration) {
+ duration = prettyMilliseconds(trackDuration, {
+ colonNotation: true,
+ secondsDecimalDigits: 0,
+ });
+ }
+
+ let totalDuration;
+
+ if (!trackTotalDuration) {
+ totalDuration = "0:00";
+ }
+ if (trackTotalDuration) {
+ totalDuration = prettyMilliseconds(trackTotalDuration, {
+ colonNotation: true,
+ secondsDecimalDigits: 0,
+ });
+ }
+
+ ctx.fillStyle = "#fff";
+ ctx.font = "30px Arial";
+ const text1X = 420;
+ const text1Y = 330;
+ ctx.fillText(trackStream ? `LIVE` : duration, text1X, text1Y);
+
+ ctx.fillStyle = "#fff";
+ ctx.font = "30px Arial";
+ const text2X = 1060;
+ const text2Y = 330;
+ ctx.fillText(trackStream ? `LIVE` : totalDuration, text2X, text2Y);
+
+ const imageSize = Math.min(canvasHeight - 80, canvasWidth - 80);
+ const imageX = 40;
+ const imageY = 40;
+ const borderRadius = 25;
+
+ ctx.filter = "blur(5px)";
+ ctx.drawImage(
+ canvas,
+ 0,
+ 0,
+ canvasWidth,
+ canvasHeight,
+ 0,
+ 0,
+ canvasWidth,
+ canvasHeight
+ );
+
+ ctx.save();
+ ctx.beginPath();
+ ctx.moveTo(imageX + borderRadius, imageY);
+ ctx.lineTo(imageX + imageSize - borderRadius, imageY);
+ ctx.quadraticCurveTo(
+ imageX + imageSize,
+ imageY,
+ imageX + imageSize,
+ imageY + borderRadius
+ );
+ ctx.lineTo(imageX + imageSize, imageY + imageSize - borderRadius);
+ ctx.quadraticCurveTo(
+ imageX + imageSize,
+ imageY + imageSize,
+ imageX + imageSize - borderRadius,
+ imageY + imageSize
+ );
+ ctx.lineTo(imageX + borderRadius, imageY + imageSize);
+ ctx.quadraticCurveTo(
+ imageX,
+ imageY + imageSize,
+ imageX,
+ imageY + imageSize - borderRadius
+ );
+ ctx.lineTo(imageX, imageY + borderRadius);
+ ctx.quadraticCurveTo(imageX, imageY, imageX + borderRadius, imageY);
+ ctx.closePath();
+ ctx.clip();
+ ctx.drawImage(imageToAdd, imageX, imageY, imageSize, imageSize);
+ ctx.restore();
+
+ const textX = imageX + imageSize + 60;
+ const textY = imageY - -60;
+
+ const maxWidth = 540;
+ const text = imageText;
+
+ const textWidth = ctx.measureText(text).width;
+
+ if (textWidth > maxWidth) {
+ const ellipsisWidth = ctx.measureText("...").width;
+
+ const availableWidth = maxWidth - ellipsisWidth;
+
+ let truncatedText = text;
+ while (ctx.measureText(truncatedText).width > availableWidth) {
+ truncatedText = truncatedText.slice(0, -1);
+ }
+
+ truncatedText += "...";
+
+ ctx.fillStyle = "#fff";
+ ctx.font = "40px Arial";
+ ctx.fillText(truncatedText, textX, textY);
+ } else {
+ ctx.fillStyle = "#fff";
+ ctx.font = "40px Arial";
+ ctx.fillText(text, textX, textY);
+ }
+ return canvas.toBuffer();
+}
+
+module.exports = { classicCard };
diff --git a/src/themes/simpleCard.js b/src/themes/simpleCard.js
new file mode 100644
index 0000000..8466d4f
--- /dev/null
+++ b/src/themes/simpleCard.js
@@ -0,0 +1,111 @@
+const { createCanvas, loadImage } = require("canvas");
+const Jimp = require("jimp");
+
+async function simpleCard({ imageBg, imageText }) {
+ const canvasWidth = 600;
+ const canvasHeight = 600;
+ const canvas = createCanvas(canvasWidth, canvasHeight);
+ const ctx = canvas.getContext("2d");
+
+ const imageToAdd = await loadImage(imageBg);
+ const imageToAdds = await Jimp.read(imageBg);
+
+ const sampleColor = imageToAdds.getPixelColor(0, 0);
+ const { r, g, b } = Jimp.intToRGBA(sampleColor);
+
+ const brightnessFactor = 0.7;
+
+ const adjustedR = Math.round(r * brightnessFactor);
+ const adjustedG = Math.round(g * brightnessFactor);
+ const adjustedB = Math.round(b * brightnessFactor);
+
+ const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
+ gradient.addColorStop(0, `rgb(${adjustedR}, ${adjustedG}, ${adjustedB})`);
+ gradient.addColorStop(1, `rgb(${adjustedR}, ${adjustedG}, ${adjustedB})`);
+
+ ctx.fillStyle = gradient;
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+ const imageSize = Math.min(canvasHeight - 200, canvasWidth - 200);
+ const imageX = (canvasWidth - imageSize) / 2;
+ const imageY = (canvasHeight - imageSize - 40) / 2;
+ const borderRadius = 25;
+
+ ctx.filter = "blur(5px)";
+ ctx.drawImage(
+ canvas,
+ 0,
+ 0,
+ canvasWidth,
+ canvasHeight,
+ 0,
+ 0,
+ canvasWidth,
+ canvasHeight
+ );
+
+ ctx.save();
+ ctx.beginPath();
+ ctx.moveTo(imageX + borderRadius, imageY);
+ ctx.lineTo(imageX + imageSize - borderRadius, imageY);
+ ctx.quadraticCurveTo(
+ imageX + imageSize,
+ imageY,
+ imageX + imageSize,
+ imageY + borderRadius
+ );
+ ctx.lineTo(imageX + imageSize, imageY + imageSize - borderRadius);
+ ctx.quadraticCurveTo(
+ imageX + imageSize,
+ imageY + imageSize,
+ imageX + imageSize - borderRadius,
+ imageY + imageSize
+ );
+ ctx.lineTo(imageX + borderRadius, imageY + imageSize);
+ ctx.quadraticCurveTo(
+ imageX,
+ imageY + imageSize,
+ imageX,
+ imageY + imageSize - borderRadius
+ );
+ ctx.lineTo(imageX, imageY + borderRadius);
+ ctx.quadraticCurveTo(imageX, imageY, imageX + borderRadius, imageY);
+ ctx.closePath();
+ ctx.clip();
+ ctx.drawImage(imageToAdd, imageX, imageY, imageSize, imageSize);
+ ctx.restore();
+
+ const textX = canvasWidth / 2;
+ const textY = imageY + imageSize + 60;
+
+ const maxWidth = 100;
+ const text = imageText;
+
+ const textWidth = ctx.measureText(text).width;
+
+ if (textWidth > maxWidth) {
+ const ellipsisWidth = ctx.measureText("...").width;
+
+ const availableWidth = maxWidth - ellipsisWidth;
+
+ let truncatedText = text;
+ while (ctx.measureText(truncatedText).width > availableWidth) {
+ truncatedText = truncatedText.slice(0, -1);
+ }
+
+ truncatedText += "...";
+
+ ctx.fillStyle = "#fff";
+ ctx.font = "35px Arial";
+ ctx.textAlign = "center";
+ ctx.fillText(truncatedText, textX, textY);
+ } else {
+ ctx.fillStyle = "#fff";
+ ctx.font = "35px Arial";
+ ctx.textAlign = "center";
+ ctx.fillText(text, textX, textY);
+ }
+ return canvas.toBuffer();
+}
+
+module.exports = { simpleCard };