Hiding messages from a discord user through javascript - Soft blocking

Viewed 1382

Blocking a user is a good feature of discord, but often enough I find myself wanting to block someone temporarily: not see their messages, but only for a certain period of time and without them knowing that I did so. Theoretically such a thing should be possible to do. I found a userscript that you are supposed to paste into the discord console once you start discord that serves the purpose of hiding messages from blocked users completely. Using the same principle, if instead of searching for blocked messages I could search for messages from a specific user, and then hide them, I could soft-block them for the duration of my current session. So the idea of this is to search all messages in a channel, check if a message was posted by a certain user that I want blocked, and if so, hide it.

To do so I have to figure out how to tie messages to their authors. There appears to be a different class for each new message that a user sends. But when a user sends multiple messages in a row, the classes are different. The first message contains the link to the user's avatar, which in turn contains the user's unique discord ID that he could be identified with. But his follow-up messages don't contain his avatar. And I can't find anything else that I could use to identify a user with except for that.

enter image description here

In the image above the classes that have groupStart contain the avatar links, whereas the classes without it are the follow-up messages from the same user that do not. Like so:

enter image description here

What kind of a loop would be able to include both the messages with some specified avatar, and the follow up messages without it?

1 Answers

As I see it, here's how you'll have to do it:

first identify the groupStart message, and then keep looking at the next messages until you reach a new groupStart message.

Luckily JavaScript keeps elements in the order that they're displayed when you use document.getElementsByClassName so you should just be able to set a variable to true when you hit the target, and then back to false when you hit a new person. This is my code:

function block(userid) {
  return setInterval(() => {
    let deleteMessages = false;

    [...document.getElementsByClassName('message-2qnXI6')].forEach(i => {
      if(i) {
        if(i.className.match('groupStart-23k01U')) {
          if(([...i.children].find(i => i.className.match('contents-2mQqc9')).children[0].src || '/1/').split('/').find(i => i.match(/^\d+$/)) === userid) {
            i.style.display = 'none'
            deleteMessages = true
          } else deleteMessages = false
        }
        else if(deleteMessages) i.style.display = 'none'
      }
    })
  
    deleteMessages = false
  }, 300)
}

The function block sets an interval for 300 seconds to:

First, get all the messages: [...document.getElementsByClassName('message-2qnXI6')]

Then for each message check to see if it's a groupStart element: if(i.className.match('groupStart-23k01U'))

If it is, it'll check to see if it's a message from the blocked user: if(([...i.children].find(i => i.className.match('contents-2mQqc9')).children[0].src || '/1/').split('/').find(i => i.match(/^\d+$/)) === userid)

If it is, it'll delete that message and set deleteMessages to true:

i.style.display = 'none'

deleteMessages = true

If it isn't, it'll set deleteMessages to false, so that the next messages don't get deleted.

Going back, if the message isn't a groupStart message, it'll check to see if deleteMessages is true (which would be the first message in the group was from a blocked user, and therefore this message is from a blocked user). If it is, it'll delete it.

Everything should be reset with a simple ctrl+r

Just copy and paste this (the minified version of my code):

function block(e){return setInterval(()=>{let t=!1;[...document.getElementsByClassName("message-2qnXI6")].forEach(n=>{n&&(n.className.match("groupStart-23k01U")?([...n.children].find(e=>e.className.match("contents-2mQqc9")).children[0].src||"/1/").split("/").find(e=>e.match(/^\d+$/))===e?(n.style.display="none",t=!0):t=!1:t&&(n.style.display="none"))}),t=!1},300)}

into the console, and then to block someone type block('<userid>') (make sure the user id is a string and not a number), and it should start working. Also, when you do, it should return a number, just type clearInterval(number) to stop it from blocking new messages.

If you're wondering about this line:

if(([...i.children].find(i => i.className.match('contents-2mQqc9')).children[0].src || '/1/').split('/').find(i => i.match(/^\d+$/)) === userid)

There's a few hackey things I did here:

I start by getting an array of all the messages children, then I find the child with the userID in it (i.className.match('contents-2mQqc9')). If I don't I just use a placeholder to avoid errors.

Then I split via /s because the user id is one of the paths. Then I find which part of the path is the user id by checking to see if it's only numbers (i.match(/^\d+$/)). Finally once I've done all that I check to see if it's the same as the userid.

Here's a quick example:

https://cdn.discordapp.com/avatars/847295719724247388/c9af8fff1110025e6aae862492b4aa29.webp?size=256 (this isn't a real link) => ['https:', '', 'cdn.discordapp.com', 'avatars', '847295719724247388', 'c9af8fff1110025e6aae862492b4aa29.webp?size=256'] => '847295719724247388' is made completely of numbers, so: '847295719724247388'

Unfortunately, if you use this on too many messages by the same person in a row discord will really glitch out, so you'll have to watch for that (note this was testing it on 1000+ messages in a row by the same person). It seems like problems start to happen at around 100, but don't become an issue until it's up to 200 - 300, and even then it'll sometimes work if you wait for a second.

Hopefully if this doesn't work for you you'll at least have an idea of what to do.

Related