Skip to content

Instantly share code, notes, and snippets.

@Qubus0
Last active November 17, 2025 10:42
Show Gist options
  • Select an option

  • Save Qubus0/90f6841aa40284a4626bfce6c1226393 to your computer and use it in GitHub Desktop.

Select an option

Save Qubus0/90f6841aa40284a4626bfce6c1226393 to your computer and use it in GitHub Desktop.
yagbdb discord bot custom command to block image spambots
{{/* === CONFIGURATION === */}}
{{/* where to log the action and deleted message */}}
{{$logChannel := 000000000000 }}
{{/* how often the same message needs to be sent in the timespan to trigger the command */}}
{{$triggerThreshold := 5 }}
{{/* the timespan between messages until they are no longer considered duplicates */}}
{{$duplicateTrackExpirationSeconds := 120 }}
{{/* how long to time out the offending user, blocks bots from spamming further */}}
{{$timeoutDurationMinutes := 720 }}
{{/* === SCRIPT START === */}}
{{/* DB keys for this user */}}
{{$userID := .User.ID}}
{{$counterKey := print "spamCounter:" $userID}}
{{$msgsKey := print "spamMsgs:" $userID}}
{{/* Fetch existing data */}}
{{$currentCounter := 0}}
{{with (dbGet $userID $counterKey)}}{{$currentCounter = .Value}}{{end}}
{{/* Add message to the stored list */}}
{{$existingMsgs := cslice}}
{{with (dbGet $userID $msgsKey)}}{{$existingMsgs = .Value}}{{end}}
{{$newMsg := dict "ID" .Message.ID "Content" .Message.Content "ChannelID" .Channel.ID}}
{{$updatedMsgs := $existingMsgs.Append $newMsg}}
{{/* Increase counter and reset DB expiration */}}
{{$newCounter := add $currentCounter 1}}
{{dbSetExpire $userID $counterKey $newCounter $duplicateTrackExpirationSeconds}}
{{dbSetExpire $userID $msgsKey $updatedMsgs $duplicateTrackExpirationSeconds}}
{{if ge (toInt $newCounter) $triggerThreshold}}
{{try}}
{{$noOutput := execAdmin "timeout" .User.Mention $timeoutDurationMinutes "Image Spam (Suspected Scambot)"}}
{{catch}}
{{sendMessage $logChannel (.Error) }}
{{end}}
{{/* Log the action */}}
{{$logMsg := (printf "**Anti-Imagescam Triggered**\n\nUser: %s \nDeleting %d messages:\n\n" .User.Mention (len $updatedMsgs))}}
{{/* Get the first message */}}
{{$firstMsg := index $updatedMsgs 0}}
{{$cleanContent := $firstMsg.Content}}
{{$embed := cembed
"description" (print $cleanContent)
"color" 16711680
"footer" (dict "text" (print "Triggered at: " currentTime))
"author" (sdict
"name" .User.Username
"icon_url" (.Member.AvatarURL "256")
)
}}
{{sendMessage $logChannel (complexMessage "content" $logMsg "embed" $embed)}}
{{/* Delete all stored messages */}}
{{range $msg := $updatedMsgs}}
{{deleteMessage (toInt64 $msg.ChannelID) (toInt64 $msg.ID) 0}}
{{end}}
{{/* Clear user data after action */}}
{{dbDel $userID $counterKey}}
{{dbDel $userID $msgsKey}}
{{end}}
@Qubus0
Copy link
Author

Qubus0 commented Sep 30, 2025

How?

We're creating a custom command with a regex trigger - so any message that follows the rules we set in the regular expression will trigger this command. yagpdb has a database built in, we're using that to count how often the same message was posted (this is a more fine grained anti spam after all). each time the message is posted, count is increased until $triggerThreshold is reached, which then deletes all the tracked messages, logs the action in $logChannel, and times the user out to prevent further spam. if there is no new duplicate message within $duplicateTrackExpirationSeconds, the database entry expires to free up space

Setup

Quick setup

  1. Open this share link in browser: https://yagpdb.xyz/cc/oiq5qEGDN7
  2. Select server and press import CC
  3. change the configuration at the top of the custom command. at least the logChannel needs to be changed

Manual Setup

under custom commands -> commands, add a new custom command with "regex" trigger

The custom command trigger is a Regex matching images hosted on discord:
.*?(?:media|cdn)\.discord(app)?\.(?:net|com)|(ibb\.co)|(\.png)|(\.jpe?g)|(\.web(p|m))|(\.gifv?)|(\.mp4)|(\.mov).*?
if you are versed in RegEx, this can be adjusted on the fly if they ever swap to other hosting or generalised to get any image

take a look at what this regex matches here https://regex101.com/r/Lm2bf5/1
in short, any message that contains one of these anywhere in the message:

  • (?:media|cdn)\.discord(app)?\.(?:net|com) -> all image files hosted by/uploaded to discord, or (that's the |)
  • (ibb\.co) -> anything on ibb.co (since they are already using other hosting services)
  • (\.png)|(\.jpe?g)|(\.web(p|m))|(\.gifv?)|(\.mp4)|(\.mov) -> any link that ends with a file format that discord embeds directly

the top section of the command reply can be adjusted by you

{{/* where to log the action and deleted message */}}
{{$logChannel := 000000000000 }}
{{/* how often the same message needs to be sent in the timespan to trigger the command */}}
{{$triggerThreshold := 5 }}
{{/* the timespan between messages until they are no longer considered duplicates */}}
{{$duplicateTrackExpirationSeconds := 120 }}
{{/* how long to time out the offending user, blocks bots from spamming further */}}
{{$timeoutDurationMinutes := 720 }}
  • $logChannel is a channel id (enable dev mode in user settings > advanced, then right click a channel > copy channel id). make sure to also add that channel to the ignored channels

Why?

This command specifically targets Discord spambots posting images to circumvent text automoderation

like this one image

The custom command targets image links specifically, because linked files are not considered attachments by discord (which could easily be caught by the complementing automod rule below)


More Automod

The custom command can be complemented with this other automoderation rule in case they switch to directly uploading images to discord instead of sending links - those will actually be caught by the "with attachments" filter.

image
  • The automod rule bans for one minute because message mass deletion is restricted to a single channel. banning deletes all messages of the same day.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment