Skip to content
This repository has been archived by the owner on Nov 15, 2024. It is now read-only.

Commit

Permalink
feat: add new themes
Browse files Browse the repository at this point in the history
  • Loading branch information
LewdHuTao committed Mar 7, 2024
1 parent 3c45d9e commit 4382b9e
Show file tree
Hide file tree
Showing 4 changed files with 365 additions and 218 deletions.
76 changes: 54 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,42 @@ npm install songcard
# or
yarn add songcard
```
<br>

## Usage

| Option | Type | Description |
|------------------------|------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
| imageBg | String | Image that will be display to the songcard. <br><br> Example: https://images-ext-1.discordapp.net/external/uw_-bWFyeXnWb11wGThe2CAbTYdrxzFqMJ2trxDIYVE/https/i.scdn.co/image/ab67616d0000b2738ad8f5243d6534e03b656c8b?width=468&height=468 <br>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`<br><br>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. |

<br>

# 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",
Expand All @@ -45,25 +66,36 @@ client.on("interactionCreate", async (message) => {

client.login("token");
```
<br>

## Usage
## 2. Simple

| Option | Type | Description |
|------------------------|------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
| imageBg | String | Image that will be display to the songcard. <br><br> Example: https://images-ext-1.discordapp.net/external/uw_-bWFyeXnWb11wGThe2CAbTYdrxzFqMJ2trxDIYVE/https/i.scdn.co/image/ab67616d0000b2738ad8f5243d6534e03b656c8b?width=468&height=468 <br>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`<br><br>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)

<br>
<br>
### Example

![](https://cdn.discordapp.com/attachments/897715616155328542/1146301148706390036/image.png)
```js
const { simpleCard } = require("songcard");
const { AttachmentBuilder } = require("discord.js");

<br>
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");
```


199 changes: 3 additions & 196 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -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 }
Loading

0 comments on commit 4382b9e

Please sign in to comment.