Skip to content

Instantly share code, notes, and snippets.

@M-logique
Created March 1, 2025 15:09
Show Gist options
  • Save M-logique/eb20bb0a120ee6fff197310c697f1a84 to your computer and use it in GitHub Desktop.
Save M-logique/eb20bb0a120ee6fff197310c697f1a84 to your computer and use it in GitHub Desktop.
Fast discord dm closer written in golang
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"sync"
"time"
)
const (
DiscordAPIBase = "https://discord.com/api/v10/"
GetDMsURL = DiscordAPIBase + "/users/@me/channels"
DeleteDMURL = DiscordAPIBase + "/channels/%s"
)
type Channel struct {
ID string `json:"id"`
Type int `json:"type"`
}
type RateLimitResponse struct {
RetryAfter float64 `json:"retry_after"`
}
func getDMs(t string) ([]Channel, error) {
client := &http.Client{}
req, err := http.NewRequest("GET", GetDMsURL, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %s", err)
}
req.Header.Set("Authorization", t)
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("there was an error making the request: %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("failed to get DMs, status: %d, response: %s", resp.StatusCode, string(body))
}
var channels []Channel
if err := json.NewDecoder(resp.Body).Decode(&channels); err != nil {
return nil, fmt.Errorf("failed to decode DMs")
}
return channels, nil
}
func deleteDM(t string, channelID string) (error) {
client := &http.Client{}
req, err := http.NewRequest("DELETE", fmt.Sprintf(DeleteDMURL, channelID), nil)
if err != nil {
return fmt.Errorf("failed to create request %v", err)
}
req.Header.Set("Authorization", t)
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("failed to delete DM: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
if resp.StatusCode == 429 {
var rateLimit RateLimitResponse
body, _ := io.ReadAll(resp.Body)
if err := json.Unmarshal(body, &rateLimit); err != nil {
time.Sleep((1 * time.Second) / 3)
// Rate limited by CloudFlare,
// so we don't have any choice except retry
return deleteDM(t, channelID)
}
fmt.Printf("Rate limit exceeded. Retrying after %.2f seconds...\n", rateLimit.RetryAfter)
time.Sleep(time.Duration(rateLimit.RetryAfter*1000) * time.Millisecond)
return deleteDM(t, channelID)
}
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("failed to delete DM, status: %d, response: %s", resp.StatusCode, string(body))
}
fmt.Println("Deleted DM channel:", channelID)
return nil
}
func main() {
var inputToken string
fmt.Print("Enter your account's token: ")
fmt.Scan(&inputToken)
fmt.Println("Fetching DM channels...")
channels, err := getDMs(inputToken)
if err != nil {
fmt.Println("There was an error fetching channels:", err)
fmt.Scanln()
return
}
if len(channels) == 0 {
fmt.Println("You don't have any dm channel!")
fmt.Scanln()
return
}
var closeQuestion string
fmt.Printf("Found %d DM channel(s), do you want to close them? (yes / no) ", len(channels))
fmt.Scan(&closeQuestion)
if closeQuestion != "yes" {
return
}
var wg sync.WaitGroup
for _, channel := range channels {
wg.Add(1)
go func (t string, channelID string) {
defer wg.Done()
err := deleteDM(t, channelID)
if err != nil {
fmt.Println("Failed to close dm:", err)
}
time.Sleep(time.Second * 4)
}(inputToken, channel.ID)
}
wg.Wait()
fmt.Println("All DM channels are closed!")
fmt.Scanln()
}
@M-logique
Copy link
Author

Binary files:

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