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

331
LINES

< > BotCompany Repo | #1023434 - Discord Include [just Discord reading & posting]

JavaX fragment (include)

import net.dv8tion.jda.core.events.guild.member.*;
import net.dv8tion.jda.core.Permission;
import net.dv8tion.jda.core.requests.restaction.MessageAction;
import net.dv8tion.jda.core.requests.RestAction;
import java.util.function.Consumer;

switchable S discordToken;
S discordBotName;
long discordBotID;
bool reactToBots = true;
transient bool sendToPostedLinesCRUD = true;

transient JDA discord;
transient Color discordImageEmbedMysteriousLineColor = colorFromHex("36393f");
transient L<IVF2<MessageChannel, S>> onPostedInChannel = syncList();
//transient bool debugPosting;

// when a discord action failed
transient Consumer<Throwable> onQueueError = error -> {
  temp enter();
  printStackTrace(error);
};

void startDiscord {
  if (!discordEnabled()) ret with print("Not enabled");
  
  vm_cleanPrints(); // avoid Swing Unicode problem
  logModuleOutput(); // good idea for chat bots

  // TODO: log JDA output going to System.out/err
  discord = discordBot(new ListenerAdapter {
    @Override
    public void onMessageUpdate(MessageUpdateEvent e) pcall {
      temp enter();
      ret if !discordEnabled() || !licensed();
      
      Message msg = e.getMessage();
      long msgID = msg.getIdLong();
      User user = e.getAuthor();
      long userID = user == null ? 0 : user.getIdLong();
      S content = e.getMessage().getContentRaw();
      MessageChannel channel = e.getChannel();
      long channelID = channel.getIdLong();
      S rendered = msgID + ": " + content;
      //print("Message edited: " + rendered);
      
      vmBus_send editedDiscordMessage(
        litmapparams(event := e, module := dm_me(), +msgID, +msg, +content,
          +channelID, +channel, +user, +userID));
          
      O lineConcept = dm_discord_lineForMsgID_unimported(msgID);
      if (lineConcept == null) ret; // logging module not enabled
      call(lineConcept, '_setField, editedText := content);
    }
    
    @Override
    public void onMessageReceived(MessageReceivedEvent e) pcall {
      temp enter();
      ret if !discordEnabled() || !licensed();
      
      // send out raw event
      vmBus_send discord_onMessageReceived(module(), e);
      
      User user = e.getAuthor();
      if (!reactToUser(user)) ret with print("Not reacting to user " + user);
      bool bot = user.isBot();

      long msgID = e.getMessage().getIdLong();
      long userID = user.getIdLong();
      Guild guild = e.getGuild();
      long guildID = toLong(call(guild, 'getIdLong);
      Member member = e.getMember();
      S userName = member == null ? null : member.getNickname(); // the changeable nick name - null sometimes?
      if (userName == null && member != null) userName = member.getEffectiveName();
      if (userName == null) userName = e.getAuthor().getName();
      
      final Message msg = e.getMessage();
      
      MessageChannel channel = e.getChannel();
      long channelID = channel.getIdLong();
      //print("Channel type: " + e.getChannelType());
      bool isPrivate = e.getChannelType() == ChannelType.PRIVATE;
      S content = trim(msg.getContentRaw());
      print("Msg from " + userName + ": " + content);

      vmBus_send incomingDiscordMessage(
        litmapparams(fromBot := bot, module := dm_me(), +msgID, +userID, +userName, event := e, +guildID, +guild, +member,
          +msg,
          +content, +isPrivate, +channelID, +channel));
    }
    
    @Override
    public void onMessageReactionAdd(MessageReactionAddEvent e) pcall {
      temp enter();
      ret if !discordEnabled() || !licensed();
      MessageReaction r = e.getReaction();
      
      User user = e.getUser();
      if (!reactToUser(user)) ret;
      bool bot = user.isBot();
      
      long msgID = r.getMessageIdLong();
      S emoji = r.getReactionEmote().getName();
      
      vmBus_send('incomingDiscordReaction, litmapparams(
        reaction := r,
        fromBot := bot, +user, userID := user.getIdLong(),
        module := dm_me(), +msgID, +emoji
      ));
    }
    
    @Override
    public void onMessageReactionRemove(MessageReactionRemoveEvent e) pcall {
      temp enter();
      ret if !discordEnabled() || !licensed();
      MessageReaction r = e.getReaction();
      
      User user = e.getUser();
      if (!reactToUser(user)) ret;
      bool bot = user.isBot();
      
      long msgID = r.getMessageIdLong();
      S emoji = r.getReactionEmote().getName();
      
      vmBus_send('discordReactionRemoved, litmapparams(
        reaction := r,
        fromBot := bot, +user, userID := user.getIdLong(),
        module := dm_me(), +msgID, +emoji
      ));
    }
    
    @Override
    public void onMessageReactionRemoveAll(MessageReactionRemoveAllEvent e) pcall {
      temp enter();
      print("TODO: onMessageReactionRemoveAll");
    }
    
    @Override
    public void onGuildMemberJoin(GuildMemberJoinEvent event) pcall {
      temp enter();
      print("Got guild join");
      ret if !discordEnabled() || !licensed();
      
      print("Join >> getting user ID");
      long userID = rcall_long getIdLong(rcall getUser(event.getMember()));
      print("Join >> sending");
      vmBus_send('discordGuildJoin, litmapparams(
        module := dm_me(), +event, +userID, guildID := discord_guildIDFromEvent_gen(event)
      ));
    }
    
    @Override
    public void onGuildMemberLeave(GuildMemberLeaveEvent event) pcall {
      temp enter();
      print("Got guild leave");
      ret if !discordEnabled() || !licensed();

      long userID = rcall_long getIdLong(rcall getUser(event.getMember()));
      vmBus_send('discordGuildLeave, litmapparams(
        module := dm_me(), +event, +userID
      ));
    }
  }, token := discordToken);
  
  dm_registerAs('liveDiscordModule);
  dm_vmBus_answerToMessage activeDiscordTokens(func -> LS { ll(discordToken) });
  pcall {
    setField(discordBotName := jda_selfUserName(discord));
    setField(discordBotID := jda_selfUserID(discord));
  }
  print("Bot name: " + discordBotName);
}

void cleanMeUp {
  if (discord != null) pcall {
    print("Shutting down discord");
    discord.shutdown();
    print("Bot shut down");
  }
  discord = null;
}

O userConcept(User user) {
  S crud = dm_gazelle_linesCRUD();
  O userConcept = dm_call(crud, 'uniqUser, user.getIdLong());
  dm_call(crud, 'cset, userConcept, litobjectarray(name := user.getName()));
  ret userConcept;
}

// API

MessageChannel getChannel(long channelID) {
  ret discord.getTextChannelById(channelID);
}


void postInChannel(long channelID, S msg) {
  postInChannel(channelID, msg, null);
}

void postInChannel(long channelID, S msg, IVF1<Message> onPost) {
  if (channelID == 0) ret;
  postInChannel(getChannel(channelID), msg, onPost);
}

void uploadFileInChannel(long channelID, File file, S fileName, S msg, IVF1<Message> onPost) {
  if (channelID == 0) ret;
  uploadFileInChannel(getChannel(channelID), file, fileName, msg, onPost);
}

void postInChannel(MessageChannel channel, S msg, IVF1<Message> onPost) {
  S originalMsg = msg;
  msg = shortenForDiscord(msg);
  if (empty(msg)) ret;
  
  S postID = !sendToPostedLinesCRUD ? null : (S) dm_pcall(gazelle_postedLinesCRUD(), 'postingLine, channel.getId(), msg);

  print("Posting in channel " + channel + ": " + msg);
  pcallFAll(onPostedInChannel, channel, msg);
  MessageAction a = channel.sendMessage(msg);
  if (msg != originalMsg)
    a.addFile(toUtf8(originalMsg), genericTextFileName());
  a.queue(m -> msgPosted(m, onPost, postID), onQueueError);
}

S genericTextFileName() {
  ret ymd_minus_hms() + ".txt";
}

void msgPosted(Message m, IVF1<Message> onPost, S postID) enter {
  if (nempty(postID))
    dm_call(gazelle_postedLinesCRUD(), 'donePosting, postID, "discord msg " + m.getId());
  long msgId = m.getIdLong();
  print("I sent msg: " + msgId);
  pcallF(onPost, m);
}

void postInChannel(S channel, S msg) {
  long id = dm_discord_channelID(channel);
  if (id == 0) fail("Channel not found: " + channel);
  postInChannel(id, msg);
}

void postInChannel(MessageChannel channel, S msg) {
  postInChannel(channel, msg, null);
}

void postImage(Map msgMap, S url) {
  postImage(msgMap, url, "");
}

void postImage(Map msgMap, S url, S description) {
  postImage((MessageChannel) get channel(msgMap), url, description);
}

void postImage(MessageChannel channel, S url, S description) {
  channel.sendMessage(
    new EmbedBuilder()
      .setImage(absoluteURL(url))
      //.setTitle(unnull(title))
      .setDescription(unnull(description))
      .setColor(discordImageEmbedMysteriousLineColor)
      .build()).queue(null, onQueueError); // TODO: posted lines
}

void editMessage(long channelID, long msgID, S text) {
  getChannel(channelID).editMessageById(str(msgID), text).queue(null, onQueueError);
}

void sendPM(long userID, S _text) {
  S text = shortenForDiscord(_text);
  if (empty(text)) ret;
  print("Sending PM to " + userID + ": " + text);
  discord.getUserById(userID).openPrivateChannel().queue(channel -> {
    channel.sendMessage(text).queue(null, onQueueError);
  }, onQueueError);
  print("PM queued");
}

void reply(Map msgMap, S text) {
  reply(msgMap, text, null);
}

void reply(Map msgMap, S text, O onPost) {
  if (empty(text = trim(text))) ret;
  postInChannel((MessageChannel) msgMap.get('channel), text, toIVF1(onPost));
}

void iAmTyping(Map msgMap) pcall {
  ((MessageChannel) msgMap.get('channel)).sendTyping().queue(null, onQueueError);
}

S startKeepAliveModule() enter {
  ret dm_discord_startKeepAliveModule(module());
}

bool reactToUser(User user) {
  bool bot = user.isBot();
  
  // don't react to other bots
  if (bot && !reactToBots) false;
  
  // don't read msgs from myself
  if (user.getIdLong() == discordBotID) false;
  
  true;
}

void uploadFileInChannel(MessageChannel channel, File file, S fileName, S msg, IVF1<Message> onPost) {
  msg = shortenForDiscord(msg);
  MessageAction a = empty(msg)
    ? channel.sendFile(file, fileName)
    : channel.sendMessage(msg).addFile(file, fileName);
  a.queue(m -> msgPosted(m, onPost, null), onQueueError);
}

void uploadFileInChannel(MessageChannel channel, byte[] data, S fileName, S msg, IVF1<Message> onPost) {
  msg = shortenForDiscord(msg);
  MessageAction a = empty(msg)
    ? channel.sendFile(data, fileName)
    : channel.sendMessage(msg).addFile(data, fileName);
  a.queue(m -> msgPosted(m, onPost, null), onQueueError);
}

void uploadFileInChannel(long channelID, byte[] data, S fileName, S msg, IVF1<Message> onPost) {
  uploadFileInChannel(getChannel(channelID), data, fileName, msg, onPost);
}

void <A> queue(RestAction<A> action) {
  action.queue(null, onQueueError);
}

Author comment

Began life as a copy of #1022869

download  show line numbers  debug dex   

Travelled to 4 computer(s): cfunsshuasjs, mqqgnosmbjvj, onxytkatvevr, tvejysmllsmz

No comments. add comment

Snippet ID: #1023434
Snippet name: Discord Include [just Discord reading & posting]
Eternal ID of this version: #1023434/90
Text MD5: a33f4c2f2910614d478354547bdd9f8c
Author: stefan
Category: javax / discord
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2019-11-04 20:59:01
Source code size: 10920 bytes / 331 lines
Pitched / IR pitched: No / No
Views / Downloads: 228 / 1299
Version history: 89 change(s)
Referenced in: [show references]