File size: 4,404 Bytes
67bf4ee
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import { Colors, EmbedBuilder, Guild, Message } from "discord.js";
import type { Command } from "../types";
import { clients } from "..";
import { getJsonFromURL } from "../utils/discohook";

export default <Command>{
  data: {
    name: "mass-dm",
    description: "Gửi tin nhắn đến toàn bộ thành viên trong server.",
    toJSON() {
      return {
        name: "mass-dm",
        description: "Gửi tin nhắn đến toàn bộ thành viên trong server.",
      };
    },
  },
  ownersOnly: true,
  execute: async (message: Message, args?: string[]) => {
    if (!message.guild || !args || args.length === 0) {
      return message.reply("Vui lòng cung cấp nội dung tin nhắn.");
    }

    const contentInput = args.join(" ").trim();
    const guild = message.guild as Guild;

    const clientsInGuild = clients.filter((client) =>
      client.guilds.cache.has(guild.id)
    );
    if (clientsInGuild.length === 0) {
      return message.reply("❌ Không có client nào trong server.");
    }

    const DISCOHOOK_URL_REGEX =
      /^(https?:\/\/)?(www\.)?(discohook\.app|discohook\.org)\/\?data=/;
    let content = contentInput;
    const embeds: any[] = [];

    if (DISCOHOOK_URL_REGEX.test(contentInput)) {
      const discohook = getJsonFromURL(contentInput);
      if (discohook) {
        if (discohook.embeds && discohook.embeds.length > 0) {
          embeds.push(...discohook.embeds);
        }
        if (discohook.content) {
          content = discohook.content;
        }
      }
    }

    const variables: Map<string, string> = new Map();
    variables.set("guild.name", guild.name);
    variables.set("guild.id", guild.id);
    variables.set("guild.memberCount", guild.memberCount.toString());

    const allMembers = guild.members.cache.filter((m) => !m.user.bot);
    const done: { clientId: string; done: number; failed: number }[] =
      clientsInGuild.map((client) => ({
        clientId: client.user?.id as string,
        done: 0,
        failed: 0,
      }));

    const getTotallDone = () => done.reduce((acc, cur) => acc + cur.done, 0);
    const getTotallFailed = () =>
      done.reduce((acc, cur) => acc + cur.failed, 0);
    const isDone = () => getTotallDone() + getTotallFailed() === allMembers.size;

    const getEmbed = () =>
      new EmbedBuilder()
        .setTitle("📬 Mass DM Status")
        .setDescription(
          `Total: ${allMembers.size}\nDone: ${getTotallDone()}\nFailed: ${getTotallFailed()}\nStatus: ${isDone() ? "✅ Done" : "⏳ In Progress"}`
        )
        .setColor(isDone() ? Colors.Green : Colors.Yellow)
        .setTimestamp();

    const statusMessage = await message.reply({
      embeds: [getEmbed()],
    });

    let clientIndex = 0;
    for (const member of allMembers.values()) {
      if (!clientsInGuild[clientIndex]) clientIndex = 0;

      const client = clientsInGuild[clientIndex];
      const clientDone = done.find((d) => d.clientId === client.user?.id)!;
      clientIndex = (clientIndex + 1) % clientsInGuild.length;

      // Tạo nội dung riêng biệt mỗi user
      const personalizedVariables = new Map(variables);
      personalizedVariables.set("user.username", member.user.username);
      personalizedVariables.set("user.id", member.user.id);
      personalizedVariables.set("user.tag", member.user.tag);
      personalizedVariables.set("user.avatar", member.user.displayAvatarURL());
      personalizedVariables.set("user.mention", member.user.toString());
      personalizedVariables.set("user.nickname", member.nickname ?? member.user.username);

      let personalizedContent = content;
      for (const [key, value] of personalizedVariables.entries()) {
        personalizedContent = personalizedContent.replace(new RegExp(`{${key}}`, "g"), value);
      }

      try {
        await client.users.send(member.user.id, {
          content: personalizedContent,
          embeds: embeds,
        });
        clientDone.done++;
      } catch (error) {
        console.error(`❌ Không gửi được đến ${member.user.tag}:`, error);
        clientDone.failed++;
      }

      try {
        await statusMessage.edit({
          embeds: [getEmbed()],
        });
      } catch (err) {
        console.error("Không thể cập nhật tiến độ:", err);
      }

      await new Promise((res) => setTimeout(res, 400)); // delay nhẹ tránh bị rate limit
    }
  },
};