diff --git a/README.md b/README.md
index 8dbc342..9364806 100644
--- a/README.md
+++ b/README.md
@@ -18,17 +18,6 @@ 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. |
@@ -37,21 +26,29 @@ yarn add songcard
## 1. Classic
-![](./src/examples/assets/card1.png)
+![](./src/assets/card1.png)
### Example
-![](./src/examples/assets/code1.png)
+![](./src/assets/code1.png)
## 2. Simple
-![](./src/examples/assets/card2.png)
+![](./src/assets/card2.png)
+
+### Example
+
+![](./src/assets/code2.png)
+
+## 3. Dynamic
+
+![](./src/assets/card3.png)
### Example
-![](./src/examples/assets/code2.png)
+![](./src/assets/code3.png)
diff --git a/package-lock.json b/package-lock.json
index 7192356..993ed54 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "songcard",
- "version": "1.2.0",
+ "version": "1.2.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "songcard",
- "version": "1.2.0",
+ "version": "1.2.1",
"license": "ISC",
"dependencies": {
"@napi-rs/canvas": "^0.1.52",
diff --git a/package.json b/package.json
index dbc40b4..3119b7d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "songcard",
- "version": "1.2.0",
+ "version": "1.2.1",
"main": "src/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
diff --git a/src/examples/assets/card1.png b/src/assets/card1.png
similarity index 100%
rename from src/examples/assets/card1.png
rename to src/assets/card1.png
diff --git a/src/examples/assets/card2.png b/src/assets/card2.png
similarity index 100%
rename from src/examples/assets/card2.png
rename to src/assets/card2.png
diff --git a/src/assets/card3.png b/src/assets/card3.png
new file mode 100644
index 0000000..347994f
Binary files /dev/null and b/src/assets/card3.png differ
diff --git a/src/examples/assets/code1.png b/src/assets/code1.png
similarity index 100%
rename from src/examples/assets/code1.png
rename to src/assets/code1.png
diff --git a/src/examples/assets/code2.png b/src/assets/code2.png
similarity index 100%
rename from src/examples/assets/code2.png
rename to src/assets/code2.png
diff --git a/src/assets/code3.png b/src/assets/code3.png
new file mode 100644
index 0000000..a5834c0
Binary files /dev/null and b/src/assets/code3.png differ
diff --git a/src/assets/soundcloud.png b/src/assets/soundcloud.png
new file mode 100644
index 0000000..49e4369
Binary files /dev/null and b/src/assets/soundcloud.png differ
diff --git a/src/assets/spotify.png b/src/assets/spotify.png
new file mode 100644
index 0000000..4e7c810
Binary files /dev/null and b/src/assets/spotify.png differ
diff --git a/src/assets/youtube.png b/src/assets/youtube.png
new file mode 100644
index 0000000..4085105
Binary files /dev/null and b/src/assets/youtube.png differ
diff --git a/src/examples/classicCard.example.js b/src/example/classicCard.example.js
similarity index 100%
rename from src/examples/classicCard.example.js
rename to src/example/classicCard.example.js
diff --git a/src/example/dynamicCard.example.js b/src/example/dynamicCard.example.js
new file mode 100644
index 0000000..01e48ee
--- /dev/null
+++ b/src/example/dynamicCard.example.js
@@ -0,0 +1,23 @@
+const { dynamicCard } = require("songcard");
+const { AttachmentBuilder } = require("discord.js");
+
+client.on("interactionCreate", async (interaction) => {
+ const cardImage = await dynamicCard({
+ thumbnailURL:
+ "https://i.scdn.co/image/ab67616d00001e0240d7efd2594a2b6bda60ea18",
+ songTitle: "What is Love",
+ songArtist: "TWICE",
+ streamProvider: "spotify",
+ trackRequester: "@lewdhutao",
+ });
+
+ const attachment = new AttachmentBuilder(cardImage, {
+ name: "card.png",
+ });
+
+ interaction.channel.send({
+ files: [attachment],
+ });
+});
+
+client.login("token");
diff --git a/src/examples/simpleCard.example.js b/src/example/simpleCard.example.js
similarity index 100%
rename from src/examples/simpleCard.example.js
rename to src/example/simpleCard.example.js
diff --git a/src/index.js b/src/index.js
index 77483ba..8255192 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,4 +1,5 @@
const { classicCard } = require("./themes/classicCard");
const { simpleCard } = require("./themes/simpleCard");
+const { dynamicCard } = require("./themes/dynamicCard")
-module.exports = { classicCard, simpleCard };
+module.exports = { classicCard, simpleCard, dynamicCard };
diff --git a/src/tests/classicCard.test.js b/src/test/classicCard.test.js
similarity index 100%
rename from src/tests/classicCard.test.js
rename to src/test/classicCard.test.js
diff --git a/src/test/dynamicCard.test.js b/src/test/dynamicCard.test.js
new file mode 100644
index 0000000..98d6913
--- /dev/null
+++ b/src/test/dynamicCard.test.js
@@ -0,0 +1,27 @@
+const fs = require("fs");
+const { dynamicCard } = require("../themes/dynamicCard");
+
+async function testdynamicCard() {
+ const thumbnailURL =
+ "https://i.scdn.co/image/ab67616d00001e0240d7efd2594a2b6bda60ea18";
+ const songTitle = "What is Love";
+ const songArtist = "TWICE";
+ const streamProvider = "spotify";
+ const trackRequester = "@lewdhutao";
+
+ try {
+ const buffer = await dynamicCard({
+ thumbnailURL,
+ songTitle,
+ songArtist,
+ streamProvider,
+ trackRequester,
+ });
+ fs.writeFileSync("dynamicCard.png", buffer);
+ console.log("Canvas generated successfully.");
+ } catch (error) {
+ console.error("Error generating canvas:", error);
+ }
+}
+
+testdynamicCard();
diff --git a/src/tests/simpleCard.test.js b/src/test/simpleCard.test.js
similarity index 100%
rename from src/tests/simpleCard.test.js
rename to src/test/simpleCard.test.js
diff --git a/src/tests/classicCard.png b/src/tests/classicCard.png
deleted file mode 100644
index bae1768..0000000
Binary files a/src/tests/classicCard.png and /dev/null differ
diff --git a/src/tests/simpleCard.png b/src/tests/simpleCard.png
deleted file mode 100644
index c275f9a..0000000
Binary files a/src/tests/simpleCard.png and /dev/null differ
diff --git a/src/themes/dynamicCard.js b/src/themes/dynamicCard.js
new file mode 100644
index 0000000..c54c196
--- /dev/null
+++ b/src/themes/dynamicCard.js
@@ -0,0 +1,178 @@
+const { createCanvas, loadImage, GlobalFonts } = require("@napi-rs/canvas");
+const path = require("path");
+
+async function dynamicCard({
+ thumbnailURL, // required
+ songTitle, // required
+ songArtist, // optional
+ streamProvider, // optional
+ trackRequester, // optional
+}) {
+ const cardWidth = 800;
+ const cardHeight = 250;
+ const backgroundColor = "#2B2D31";
+
+ const canvas = createCanvas(cardWidth, cardHeight);
+ const ctx = canvas.getContext("2d");
+
+ const fontPath = path.join(__dirname, "..", "fonts", "ArialUnicodeMS.ttf");
+ GlobalFonts.registerFromPath(fontPath, "ArialUnicodeMS");
+
+ function roundRect(ctx, x, y, width, height, radius, fill, stroke) {
+ if (typeof stroke === "undefined") {
+ stroke = true;
+ }
+ if (typeof radius === "undefined") {
+ radius = 5;
+ }
+ if (typeof radius === "number") {
+ radius = { tl: radius, tr: radius, br: radius, bl: radius };
+ } else {
+ var defaultRadius = { tl: 0, tr: 0, br: 0, bl: 0 };
+ for (var 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();
+ }
+ }
+
+ ctx.fillStyle = backgroundColor;
+ roundRect(ctx, 0, 0, cardWidth, cardHeight, 20, true, false);
+
+ const thumbnailImage = await loadImage(thumbnailURL);
+
+ const padding = 20;
+ const thumbnailSize = cardHeight - 2 * padding;
+
+ ctx.save();
+ ctx.beginPath();
+ ctx.moveTo(cardWidth - thumbnailSize - padding + 20, padding);
+ ctx.arcTo(
+ cardWidth - padding,
+ padding,
+ cardWidth - padding,
+ padding + 20,
+ 20
+ );
+ ctx.arcTo(
+ cardWidth - padding,
+ cardHeight - padding,
+ cardWidth - padding - 20,
+ cardHeight - padding,
+ 20
+ );
+ ctx.arcTo(
+ cardWidth - thumbnailSize - padding,
+ cardHeight - padding,
+ cardWidth - thumbnailSize - padding,
+ cardHeight - padding - 20,
+ 20
+ );
+ ctx.arcTo(
+ cardWidth - thumbnailSize - padding,
+ padding,
+ cardWidth - thumbnailSize - padding + 20,
+ padding,
+ 20
+ );
+ ctx.closePath();
+ ctx.clip();
+ ctx.drawImage(
+ thumbnailImage,
+ cardWidth - thumbnailSize - padding,
+ padding,
+ thumbnailSize,
+ thumbnailSize
+ );
+ ctx.restore();
+
+ const streamProviderIcons = {
+ spotify: path.join(__dirname, "..", "assets", "spotify.png"),
+ youtube: path.join(__dirname, "..", "assets", "youtube.png"),
+ soundcloud: path.join(__dirname, "..", "assets", "soundcloud.png"),
+ };
+
+ if (streamProvider && streamProviderIcons[streamProvider.toLowerCase()]) {
+ const providerIcon = await loadImage(
+ streamProviderIcons[streamProvider.toLowerCase()]
+ );
+ const iconSize = 30;
+ const iconPadding = 10;
+ ctx.save();
+ ctx.beginPath();
+ ctx.arc(
+ cardWidth - padding - iconPadding - iconSize / 2,
+ cardHeight - padding - iconPadding - iconSize / 2,
+ iconSize / 2,
+ 0,
+ Math.PI * 2
+ );
+ ctx.closePath();
+ ctx.clip();
+ ctx.drawImage(
+ providerIcon,
+ cardWidth - padding - iconPadding - iconSize,
+ cardHeight - padding - iconPadding - iconSize,
+ iconSize,
+ iconSize
+ );
+ ctx.restore();
+ }
+
+ ctx.fillStyle = "white";
+ ctx.font = "bold 35px 'ArialUnicodeMS'";
+ ctx.textAlign = "left";
+ ctx.textBaseline = "top";
+
+ const maxWidth = cardWidth - thumbnailSize - padding * 2;
+ let truncatedTitle = songTitle;
+
+ while (ctx.measureText(truncatedTitle).width > maxWidth) {
+ truncatedTitle = truncatedTitle.slice(0, -1);
+ }
+
+ if (truncatedTitle.length < songTitle.length) {
+ truncatedTitle = truncatedTitle.slice(0, -3) + "...";
+ }
+
+ ctx.fillText(truncatedTitle, padding + 10, padding + 20);
+
+ ctx.fillStyle = "#A79D9D";
+ ctx.font = "25px 'ArialUnicodeMS'";
+
+ ctx.fillText(songArtist, padding + 10, padding + 70);
+
+ ctx.font = "20px 'ArialUnicodeMS'";
+ ctx.fillText(
+ `Requested by: ${trackRequester}`,
+ padding + 10,
+ cardHeight - padding - 20
+ );
+
+ const buffer = canvas.toBuffer("image/png");
+
+ return buffer;
+}
+
+module.exports = { dynamicCard };