musicalcard
Version:
Generate beautiful, customizable music cards for Discord bots, web apps, and more. Supports multiple styles (classic, classic-adv, dynamic) and platform icons (Spotify, YouTube, SoundCloud, Apple Music, etc.)
76 lines (75 loc) • 2.72 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateClassicCard = generateClassicCard;
const canvas_1 = require("canvas");
const path_1 = __importDefault(require("path"));
async function generateClassicCard(song, options = {}) {
const width = 1000;
const height = 300;
const canvas = (0, canvas_1.createCanvas)(width, height);
const ctx = canvas.getContext('2d');
// Background
ctx.fillStyle = options.theme === 'light' ? '#fff' : '#181818';
ctx.fillRect(0, 0, width, height);
// Rounded corners
if (options.rounded) {
ctx.save();
ctx.beginPath();
ctx.moveTo(20, 0);
ctx.arcTo(width, 0, width, height, 40);
ctx.arcTo(width, height, 0, height, 40);
ctx.arcTo(0, height, 0, 0, 40);
ctx.arcTo(0, 0, width, 0, 40);
ctx.closePath();
ctx.clip();
}
// Album cover
const coverImg = await (0, canvas_1.loadImage)(song.cover);
ctx.drawImage(coverImg, 40, 40, 220, 220);
// Platform icon (top right)
if (options.platform) {
const iconPath = path_1.default.join(__dirname, '../../assets', `${options.platform}.png`);
try {
const icon = await (0, canvas_1.loadImage)(iconPath);
ctx.drawImage(icon, 900, 20, 64, 64);
}
catch (e) {
// ignore if icon not found
}
}
// Song info
ctx.font = 'bold 36px Sans-serif';
ctx.fillStyle = options.accentColor || '#e74c3c';
ctx.textAlign = 'left';
ctx.fillText(song.title, 300, 110);
ctx.font = '36px Sans-serif';
ctx.fillStyle = '#b3b3b3';
ctx.fillText(`By ${song.artist}`, 300, 170);
// Progress bar
const barY = 240;
const barX = 300;
const barWidth = 600;
const barHeight = 18;
ctx.fillStyle = '#404040';
ctx.fillRect(barX, barY, barWidth, barHeight);
ctx.fillStyle = options.accentColor || '#e74c3c';
ctx.fillRect(barX, barY, (song.progress / song.duration) * barWidth, barHeight);
// Progress times
ctx.font = 'bold 24px Sans-serif';
ctx.fillStyle = '#fff';
ctx.textAlign = 'left';
ctx.fillText(formatTime(song.progress), barX, barY + 40);
ctx.textAlign = 'right';
ctx.fillText(formatTime(song.duration), barX + barWidth, barY + 40);
if (options.rounded)
ctx.restore();
return canvas.toBuffer('image/png');
}
function formatTime(sec) {
const m = Math.floor(sec / 60);
const s = Math.floor(sec % 60);
return `${m.toString().padStart(1, '0')}:${s.toString().padStart(2, '0')}`;
}