Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

344
LINES

< > BotCompany Repo | #1026292 // Discord Include [just Discord reading & posting, JDA 4.0]

JavaX fragment (include)

1  
import net.dv8tion.jda.api.events.guild.member.*;
2  
import net.dv8tion.jda.api.Permission;
3  
import net.dv8tion.jda.api.requests.restaction.MessageAction;
4  
import net.dv8tion.jda.api.requests.RestAction;
5  
import java.util.function.Consumer;
6  
7  
switchable S discordToken;
8  
S discordBotName;
9  
long discordBotID;
10  
bool reactToBots = true;
11  
transient bool sendToPostedLinesCRUD = true;
12  
transient bool escapeAtEveryone;
13  
transient bool membersIntent; // is members intent needed (reacting to user join/leave)
14  
15  
transient JDA discord;
16  
transient Color discordImageEmbedMysteriousLineColor = colorFromHex("36393f");
17  
transient L<IVF2<MessageChannel, S>> onPostedInChannel = syncList();
18  
//transient bool debugPosting;
19  
20  
// when a discord action failed
21  
transient Consumer<Throwable> onQueueError = error -> {
22  
  temp enter();
23  
  printStackTrace(error);
24  
};
25  
26  
void startDiscord {
27  
  if (!discordEnabled()) ret with print("Not enabled");
28  
  
29  
  vm_cleanPrints(); // avoid Swing Unicode problem
30  
  logModuleOutput(); // good idea for chat bots
31  
32  
  // TODO: log JDA output going to System.out/err
33  
  discord = discordBot40(new ListenerAdapter {
34  
    @Override
35  
    public void onMessageUpdate(MessageUpdateEvent e) pcall {
36  
      temp enter();
37  
      ret if !discordEnabled() || !licensed();
38  
      
39  
      Message msg = e.getMessage();
40  
      long msgID = msg.getIdLong();
41  
      User user = e.getAuthor();
42  
      long userID = user == null ? 0 : user.getIdLong();
43  
      S content = e.getMessage().getContentRaw();
44  
      MessageChannel channel = e.getChannel();
45  
      long channelID = channel.getIdLong();
46  
      S rendered = msgID + ": " + content;
47  
      //print("Message edited: " + rendered);
48  
      
49  
      vmBus_send editedDiscordMessage(
50  
        litmapparams(event := e, module := dm_me(), +msgID, +msg, +content,
51  
          +channelID, +channel, +user, +userID));
52  
          
53  
      O lineConcept = dm_discord_lineForMsgID_unimported(msgID);
54  
      if (lineConcept == null) ret; // logging module not enabled
55  
      call(lineConcept, '_setField, editedText := content);
56  
    }
57  
    
58  
    @Override
59  
    public void onMessageReceived(MessageReceivedEvent e) pcall {
60  
      temp enter();
61  
      ret if !discordEnabled() || !licensed();
62  
      
63  
      // send out raw event
64  
      vmBus_send discord_onMessageReceived(module(), e);
65  
      
66  
      User user = e.getAuthor();
67  
      if (!reactToUser(user)) ret with print("Not reacting to user " + user);
68  
      bool bot = user.isBot();
69  
70  
      long msgID = e.getMessage().getIdLong();
71  
      long userID = user.getIdLong();
72  
      Guild guild = e.isFromType(ChannelType.TEXT) ? e.getGuild() : null;
73  
      long guildID = toLong(call(guild, 'getIdLong);
74  
      Member member = e.getMember();
75  
      S userName = member == null ? null : member.getNickname(); // the changeable nick name - null sometimes?
76  
      if (userName == null && member != null) userName = member.getEffectiveName();
77  
      if (userName == null) userName = e.getAuthor().getName();
78  
      
79  
      final Message msg = e.getMessage();
80  
      
81  
      MessageChannel channel = e.getChannel();
82  
      long channelID = channel.getIdLong();
83  
      //print("Channel type: " + e.getChannelType());
84  
      bool isPrivate = e.getChannelType() == ChannelType.PRIVATE;
85  
      S content = trim(msg.getContentRaw());
86  
      print("Msg from " + userName + ": " + content);
87  
88  
      vmBus_send incomingDiscordMessage(
89  
        litmapparams(fromBot := bot, module := dm_me(), +msgID, +userID, +userName, event := e, +guildID, +guild, +member,
90  
          +msg,
91  
          +content, +isPrivate, +channelID, +channel));
92  
    }
93  
    
94  
    @Override
95  
    public void onMessageReactionAdd(MessageReactionAddEvent e) pcall {
96  
      temp enter();
97  
      ret if !discordEnabled() || !licensed();
98  
      MessageReaction r = e.getReaction();
99  
      
100  
      User user = e.getUser();
101  
      if (!reactToUser(user)) ret;
102  
      bool bot = user.isBot();
103  
      
104  
      long msgID = r.getMessageIdLong();
105  
      S emoji = r.getReactionEmote().getName();
106  
      
107  
      vmBus_send('incomingDiscordReaction, litmapparams(
108  
        reaction := r,
109  
        fromBot := bot, +user, userID := user.getIdLong(),
110  
        module := dm_me(), +msgID, +emoji
111  
      ));
112  
    }
113  
    
114  
    @Override
115  
    public void onMessageReactionRemove(MessageReactionRemoveEvent e) pcall {
116  
      temp enter();
117  
      ret if !discordEnabled() || !licensed();
118  
      MessageReaction r = e.getReaction();
119  
      
120  
      User user = e.getUser();
121  
      if (!reactToUser(user)) ret;
122  
      bool bot = user.isBot();
123  
      
124  
      long msgID = r.getMessageIdLong();
125  
      S emoji = r.getReactionEmote().getName();
126  
      
127  
      vmBus_send('discordReactionRemoved, litmapparams(
128  
        reaction := r,
129  
        fromBot := bot, +user, userID := user.getIdLong(),
130  
        module := dm_me(), +msgID, +emoji
131  
      ));
132  
    }
133  
    
134  
    @Override
135  
    public void onMessageReactionRemoveAll(MessageReactionRemoveAllEvent e) pcall {
136  
      temp enter();
137  
      print("TODO: onMessageReactionRemoveAll");
138  
    }
139  
    
140  
    @Override
141  
    public void onGuildMemberJoin(GuildMemberJoinEvent event) pcall {
142  
      temp enter();
143  
      print("Got guild join");
144  
      ret if !discordEnabled() || !licensed();
145  
      
146  
      print("Join >> getting user ID");
147  
      long userID = rcall_long getIdLong(rcall getUser(event.getMember()));
148  
      print("Join >> sending");
149  
      vmBus_send('discordGuildJoin, litmapparams(
150  
        module := dm_me(), +event, +userID, guildID := discord_guildIDFromEvent_gen(event)
151  
      ));
152  
    }
153  
    
154  
    @Override
155  
    public void onGuildMemberLeave(GuildMemberLeaveEvent event) pcall {
156  
      temp enter();
157  
      print("Got guild leave");
158  
      ret if !discordEnabled() || !licensed();
159  
160  
      long userID = rcall_long getIdLong(rcall getUser(event.getMember()));
161  
      vmBus_send('discordGuildLeave, litmapparams(
162  
        module := dm_me(), +event, +userID
163  
      ));
164  
    } // end of JDA listener
165  
  }, token := discordToken, +membersIntent);
166  
  
167  
  dm_registerAs('liveDiscordModule);
168  
  dm_vmBus_answerToMessage activeDiscordTokens(func -> LS { ll(discordToken) });
169  
  pcall {
170  
    setField(discordBotName := jda_selfUserName(discord));
171  
    setField(discordBotID := jda_selfUserID(discord));
172  
  }
173  
  print("Bot name: " + discordBotName);
174  
}
175  
176  
void cleanMeUp {
177  
  if (discord != null) pcall {
178  
    print("Shutting down discord");
179  
    discord.shutdown();
180  
    print("Bot shut down");
181  
  }
182  
  discord = null;
183  
}
184  
185  
O userConcept(User user) {
186  
  S crud = dm_gazelle_linesCRUD();
187  
  O userConcept = dm_call(crud, 'uniqUser, user.getIdLong());
188  
  dm_call(crud, 'cset, userConcept, litobjectarray(name := user.getName()));
189  
  ret userConcept;
190  
}
191  
192  
// API
193  
194  
MessageChannel getChannel(long channelID) {
195  
  ret discord.getTextChannelById(channelID);
196  
}
197  
198  
199  
void postInChannel(long channelID, S msg) {
200  
  postInChannel(channelID, msg, null);
201  
}
202  
203  
void postInChannel(long channelID, S msg, IVF1<Message> onPost) {
204  
  if (channelID == 0) ret;
205  
  postInChannel(getChannel(channelID), msg, onPost);
206  
}
207  
208  
// returns null for your convenience
209  
S uploadFileInChannel(long channelID, File file, S fileName, S msg, IVF1<Message> onPost) {
210  
  if (channelID == 0) null;
211  
  ret uploadFileInChannel(getChannel(channelID), file, fileName, msg, onPost);
212  
}
213  
214  
void postInChannel(MessageChannel channel, S msg, IVF1<Message> onPost) {
215  
  S originalMsg = msg;
216  
  msg = ecapeAndShortenForDiscord(msg);
217  
  if (empty(msg)) ret;
218  
  
219  
  S postID = !sendToPostedLinesCRUD ? null : (S) dm_pcall(gazelle_postedLinesCRUD(), 'postingLine, channel.getId(), msg);
220  
221  
  print("Posting in channel " + channel + ": " + msg);
222  
  pcallFAll(onPostedInChannel, channel, msg);
223  
  MessageAction a = channel.sendMessage(msg);
224  
  if (msg != originalMsg)
225  
    a.addFile(toUtf8(originalMsg), genericTextFileName());
226  
  a.queue(m -> msgPosted(m, onPost, postID), onQueueError);
227  
}
228  
229  
S genericTextFileName() {
230  
  ret "full-output-" + ymd_minus_hms() + ".txt";
231  
}
232  
233  
void msgPosted(Message m, IVF1<Message> onPost, S postID) enter {
234  
  if (nempty(postID))
235  
    dm_call(gazelle_postedLinesCRUD(), 'donePosting, postID, "discord msg " + m.getId());
236  
  long msgId = m.getIdLong();
237  
  print("I sent msg: " + msgId);
238  
  pcallF(onPost, m);
239  
}
240  
241  
void postInChannel(S channel, S msg) {
242  
  long id = dm_discord_channelID(channel);
243  
  if (id == 0) fail("Channel not found: " + channel);
244  
  postInChannel(id, msg);
245  
}
246  
247  
void postInChannel(MessageChannel channel, S msg) {
248  
  postInChannel(channel, msg, null);
249  
}
250  
251  
void postImage(Map msgMap, S url) {
252  
  postImage(msgMap, url, "");
253  
}
254  
255  
void postImage(Map msgMap, S url, S description) {
256  
  postImage((MessageChannel) get channel(msgMap), url, description);
257  
}
258  
259  
void postImage(MessageChannel channel, S url, S description) {
260  
  print("Posting image: " + url);
261  
  channel.sendMessage(
262  
    new EmbedBuilder()
263  
      .setImage(absoluteURL(url))
264  
      //.setTitle(unnull(title))
265  
      .setDescription(unnull(description))
266  
      .setColor(discordImageEmbedMysteriousLineColor)
267  
      .build()).queue(null, onQueueError); // TODO: posted lines
268  
}
269  
270  
void editMessage(long channelID, long msgID, S text) {
271  
  getChannel(channelID).editMessageById(str(msgID), text).queue(null, onQueueError);
272  
}
273  
274  
void sendPM(long userID, S _text) {
275  
  S text = ecapeAndShortenForDiscord(_text);
276  
  if (empty(text)) ret;
277  
  print("Sending PM to " + userID + ": " + text);
278  
  discord.getUserById(userID).openPrivateChannel().queue(channel -> {
279  
    channel.sendMessage(text).queue(null, onQueueError);
280  
  }, onQueueError);
281  
  print("PM queued");
282  
}
283  
284  
void reply(Map msgMap, S text) {
285  
  reply(msgMap, text, null);
286  
}
287  
288  
void reply(Map msgMap, S text, O onPost) {
289  
  if (empty(text = trim(text))) ret;
290  
  postInChannel((MessageChannel) msgMap.get('channel), text, toIVF1(onPost));
291  
}
292  
293  
void iAmTyping(Map msgMap) pcall {
294  
  ((MessageChannel) msgMap.get('channel)).sendTyping().queue(null, onQueueError);
295  
}
296  
297  
S startKeepAliveModule() enter {
298  
  ret dm_discord_startKeepAliveModule(module());
299  
}
300  
301  
bool reactToUser(User user) {
302  
  bool bot = user.isBot();
303  
  
304  
  // don't react to other bots
305  
  if (bot && !reactToBots) false;
306  
  
307  
  // don't read msgs from myself
308  
  if (user.getIdLong() == discordBotID) false;
309  
  
310  
  true;
311  
}
312  
313  
S ecapeAndShortenForDiscord(S s) {
314  
  if (escapeAtEveryone) s = escapeAtEveryone(s);
315  
  ret shortenForDiscord(s);
316  
}
317  
318  
// returns null for your convenience
319  
S uploadFileInChannel(MessageChannel channel, File file, S fileName, S msg, IVF1<Message> onPost) {
320  
  msg = ecapeAndShortenForDiscord(msg);
321  
  MessageAction a = empty(msg)
322  
    ? channel.sendFile(file, fileName)
323  
    : channel.sendMessage(msg).addFile(file, fileName);
324  
  a.queue(m -> msgPosted(m, onPost, null), onQueueError);
325  
  null;
326  
}
327  
328  
// returns null... you know the drill
329  
S uploadFileInChannel(MessageChannel channel, byte[] data, S fileName, S msg, IVF1<Message> onPost) {
330  
  msg = ecapeAndShortenForDiscord(msg);
331  
  MessageAction a = empty(msg)
332  
    ? channel.sendFile(data, fileName)
333  
    : channel.sendMessage(msg).addFile(data, fileName);
334  
  a.queue(m -> msgPosted(m, onPost, null), onQueueError);
335  
  null;
336  
}
337  
338  
S uploadFileInChannel(long channelID, byte[] data, S fileName, S msg, IVF1<Message> onPost) {
339  
  ret uploadFileInChannel(getChannel(channelID), data, fileName, msg, onPost);
340  
}
341  
342  
void <A> queue(RestAction<A> action) {
343  
  action.queue(null, onQueueError);
344  
}

Author comment

Began life as a copy of #1023434

download  show line numbers  debug dex  old transpilations   

Travelled to 9 computer(s): bhatertpkbcr, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, qsqiayxyrbia, tvejysmllsmz, vouqrxazstgt, xrpafgyirdlv

No comments. add comment

Snippet ID: #1026292
Snippet name: Discord Include [just Discord reading & posting, JDA 4.0]
Eternal ID of this version: #1026292/7
Text MD5: a962d593abbc41e6e3d6a50282090db6
Author: stefan
Category: javax / discord
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2021-01-26 05:22:56
Source code size: 11454 bytes / 344 lines
Pitched / IR pitched: No / No
Views / Downloads: 303 / 631
Version history: 6 change(s)
Referenced in: [show references]