← back to browse
goat command

propose

Romantic proposal with profile pictures

0
views
0
likes
0
installs
raw source
const axios = require("axios");
const fs = require("fs-extra");
const path = require("path");
const { createCanvas, loadImage } = require("canvas");

module.exports = {
  config: {
    name: "propose",
    version: "1.0.0",
    author: "Mohammad Maruf",
    countDown: 10,
    role: 0,
    description: "Romantic proposal with profile pictures",
    category: "love",
    guide: {
      en: "{pn} @mention | Reply | [uid]"
    }
  },

  onStart: async function ({
    api,
    event,
    args,
    usersData
  }) {

    const {
      threadID,
      messageID,
      senderID,
      mentions,
      type,
      messageReply
    } = event;

    // ==========================================
    // TARGET DETECTION
    // ==========================================

    let targetID;

    // Reply
    if (
      type === "message_reply" &&
      messageReply
    ) {
      targetID = messageReply.senderID;
    }

    // Mention
    else if (
      mentions &&
      Object.keys(mentions).length > 0
    ) {
      targetID =
        Object.keys(mentions)[0];
    }

    // UID
    else if (
      args &&
      args[0]
    ) {
      targetID = args[0];
    }

    if (!targetID) {
      return api.sendMessage(
        "💌 কাকে propose করবে?\n\n" +
        "👤 কাউকে mention করো\n" +
        "↩️ অথবা তার message-এ reply দাও! ❤️",
        threadID,
        messageID
      );
    }

    // ==========================================
    // SELF CHECK
    // ==========================================

    if (
      String(targetID) ===
      String(senderID)
    ) {
      return api.sendMessage(
        "😂 নিজেকেই propose করছো?\n\n" +
        "নিজের প্রেমে পড়ে গেছো নাকি? 🫠❤️",
        threadID,
        messageID
      );
    }

    try {

      // ==========================================
      // USER INFORMATION
      // ==========================================

      const [
        senderInfo,
        targetInfo
      ] = await Promise.all([
        usersData.get(senderID),
        usersData.get(targetID)
      ]);

      const senderName =
        senderInfo?.name ||
        "The Boy";

      const targetName =
        targetInfo?.name ||
        "The Girl";

      // ==========================================
      // BACKGROUND IMAGE
      // ==========================================

      const bgURL =
        "https://i.ibb.co/spGW0X4W/2a692ed961de.jpg";

      // ==========================================
      // FACEBOOK PROFILE IMAGE
      // ==========================================

      const getAvatar = (uid) =>
        `https://graph.facebook.com/${uid}/picture` +
        `?width=512&height=512` +
        `&access_token=6628568379%7Cc1e620fa708a1d5696fb991c1bde5662`;

      // ==========================================
      // DOWNLOAD IMAGES
      // ==========================================

      const [
        bgResponse,
        boyResponse,
        girlResponse
      ] = await Promise.all([

        axios.get(
          bgURL,
          {
            responseType: "arraybuffer",
            timeout: 20000
          }
        ),

        axios.get(
          getAvatar(senderID),
          {
            responseType: "arraybuffer",
            timeout: 20000
          }
        ),

        axios.get(
          getAvatar(targetID),
          {
            responseType: "arraybuffer",
            timeout: 20000
          }
        )

      ]);

      // ==========================================
      // LOAD IMAGES
      // ==========================================

      const background =
        await loadImage(
          bgResponse.data
        );

      const boyAvatar =
        await loadImage(
          boyResponse.data
        );

      const girlAvatar =
        await loadImage(
          girlResponse.data
        );

      // ==========================================
      // CANVAS
      // ==========================================

      const WIDTH = background.width;
      const HEIGHT = background.height;

      const canvas =
        createCanvas(
          WIDTH,
          HEIGHT
        );

      const ctx =
        canvas.getContext("2d");

      // ==========================================
      // ORIGINAL BACKGROUND
      // ==========================================

      ctx.drawImage(
        background,
        0,
        0,
        WIDTH,
        HEIGHT
      );

      // ==========================================
      // DRAW PROFILE FUNCTION
      // ==========================================

      function drawProfile(
        image,
        x,
        y,
        size
      ) {

        const radius =
          size / 2;

        // ------------------------------
        // Outer glow
        // ------------------------------

        ctx.save();

        ctx.shadowColor =
          "rgba(255, 20, 70, 0.95)";

        ctx.shadowBlur =
          18;

        ctx.beginPath();

        ctx.arc(
          x,
          y,
          radius + 5,
          0,
          Math.PI * 2
        );

        ctx.fillStyle =
          "#ffffff";

        ctx.fill();

        ctx.restore();

        // ------------------------------
        // Red border
        // ------------------------------

        ctx.beginPath();

        ctx.arc(
          x,
          y,
          radius + 3,
          0,
          Math.PI * 2
        );

        ctx.fillStyle =
          "#e51b3e";

        ctx.fill();

        // ------------------------------
        // White inner border
        // ------------------------------

        ctx.beginPath();

        ctx.arc(
          x,
          y,
          radius + 1,
          0,
          Math.PI * 2
        );

        ctx.fillStyle =
          "#ffffff";

        ctx.fill();

        // ------------------------------
        // Clip avatar
        // ------------------------------

        ctx.save();

        ctx.beginPath();

        ctx.arc(
          x,
          y,
          radius,
          0,
          Math.PI * 2
        );

        ctx.clip();

        ctx.drawImage(
          image,
          x - radius,
          y - radius,
          size,
          size
        );

        ctx.restore();

        // ------------------------------
        // Highlight
        // ------------------------------

        ctx.save();

        ctx.globalAlpha =
          0.22;

        ctx.fillStyle =
          "#ffffff";

        ctx.beginPath();

        ctx.arc(
          x - radius * 0.32,
          y - radius * 0.35,
          radius * 0.16,
          0,
          Math.PI * 2
        );

        ctx.fill();

        ctx.restore();
      }

      // ==========================================
      // EXACT PROFILE POSITIONS
      // ==========================================
      //
      // Image = 480 x 640
      //
      // GIRL FACE:
      // X ≈ 153
      // Y ≈ 169
      //
      // BOY FACE:
      // X ≈ 315
      // Y ≈ 267
      //
      // ==========================================

      // 👩 Mention / Reply target
      // Girl's face

      drawProfile(
        girlAvatar,
        153,
        169,
        58
      );

      // 👨 Command sender
      // Boy's face

      drawProfile(
        boyAvatar,
        315,
        267,
        58
      );

      // ==========================================
      // SMALL HEART
      // ==========================================

      function drawHeart(
        x,
        y,
        size
      ) {

        ctx.save();

        ctx.shadowColor =
          "#ff1744";

        ctx.shadowBlur =
          10;

        ctx.fillStyle =
          "#ff1744";

        ctx.beginPath();

        ctx.moveTo(
          x,
          y + size * 0.3
        );

        ctx.bezierCurveTo(
          x - size * 0.9,
          y - size * 0.3,
          x - size * 0.65,
          y - size,
          x,
          y - size * 0.35
        );

        ctx.bezierCurveTo(
          x + size * 0.65,
          y - size,
          x + size * 0.9,
          y - size * 0.3,
          x,
          y + size * 0.3
        );

        ctx.fill();

        ctx.restore();
      }

      drawHeart(
        235,
        215,
        10
      );

      // ==========================================
      // NAME LABEL
      // ==========================================

      function drawLabel(
        name,
        x,
        y,
        width
      ) {

        ctx.save();

        ctx.fillStyle =
          "rgba(0,0,0,0.65)";

        ctx.beginPath();

        ctx.roundRect(
          x - width / 2,
          y - 13,
          width,
          26,
          13
        );

        ctx.fill();

        ctx.strokeStyle =
          "rgba(255,255,255,0.8)";

        ctx.lineWidth =
          1;

        ctx.stroke();

        ctx.textAlign =
          "center";

        ctx.fillStyle =
          "#ffffff";

        ctx.font =
          "bold 11px Arial";

        let shortName =
          name;

        if (
          shortName.length > 20
        ) {
          shortName =
            shortName.substring(
              0,
              18
            ) + "...";
        }

        ctx.fillText(
          shortName,
          x,
          y + 4
        );

        ctx.restore();
      }

      // Girl name

      drawLabel(
        targetName,
        153,
        211,
        120
      );

      // Boy name

      drawLabel(
        senderName,
        315,
        309,
        120
      );

      // ==========================================
      // SMALL "BOY / GIRL" LABEL
      // ==========================================

      ctx.textAlign =
        "center";

      ctx.font =
        "bold 9px Arial";

      ctx.fillStyle =
        "#ffffff";

      ctx.fillText(
        "💗 GIRL",
        153,
        228
      );

      ctx.fillText(
        "💙 BOY",
        315,
        326
      );

      // ==========================================
      // SAVE
      // ==========================================

      const cacheDir =
        path.join(
          __dirname,
          "cache"
        );

      if (
        !fs.existsSync(cacheDir)
      ) {
        fs.mkdirSync(
          cacheDir,
          {
            recursive: true
          }
        );
      }

      const outputPath =
        path.join(
          cacheDir,
          `propose_${Date.now()}.png`
        );

      fs.writeFileSync(
        outputPath,
        canvas.toBuffer(
          "image/png"
        )
      );

      // ==========================================
      // SEND MESSAGE
      // ==========================================

      return api.sendMessage(
        {
          body:
            `💌 𝐏𝐑𝐎𝐏𝐎𝐒𝐀𝐋 𝐀𝐋𝐄𝐑𝐓 💌\n\n` +
            `👨 ${senderName}\n` +
            `❤️ is proposing to\n` +
            `👩 ${targetName}\n\n` +
            `💍 Will she say YES? 👀❤️`,

          attachment:
            fs.createReadStream(
              outputPath
            )
        },

        threadID,

        () => {

          try {

            if (
              fs.existsSync(
                outputPath
              )
            ) {
              fs.unlinkSync(
                outputPath
              );
            }

          } catch (err) {
            console.error(
              "Cleanup Error:",
              err
            );
          }

        },

        messageID
      );

    } catch (error) {

      console.error(
        "PROPOSE ERROR:",
        error
      );

      return api.sendMessage(
        "❌ Proposal image তৈরি করতে সমস্যা হয়েছে।\n\n" +
        "আবার try করো। ❤️",
        threadID,
        messageID
      );
    }
  }
};

View raw file