Skip to content

Instantly share code, notes, and snippets.

@sug0
Created December 28, 2019 21:28
Show Gist options
  • Select an option

  • Save sug0/448612f9a14f2d2309e0ebf43a7ea45f to your computer and use it in GitHub Desktop.

Select an option

Save sug0/448612f9a14f2d2309e0ebf43a7ea45f to your computer and use it in GitHub Desktop.
Download discord channel messages
package main
import (
"os"
"encoding/gob"
"compress/gzip"
"fmt"
"github.com/bwmarrin/discordgo"
)
func main() {
f, err := os.Open(os.Args[1])
if err != nil {
panic(err)
}
defer f.Close()
gz, err := gzip.NewReader(f)
if err != nil {
panic(err)
}
defer gz.Close()
var messages []*discordgo.Message
err = gob.NewDecoder(gz).Decode(&messages)
if err != nil {
panic(err)
}
for _, m := range messages {
fmt.Printf("[id=%s] %q said at %s: %s\n", m.ID, m.Author.Username, m.Timestamp, m.Content)
}
}
package main
import (
"os"
"os/signal"
"sort"
"time"
"encoding/gob"
"compress/gzip"
"path/filepath"
"flag"
"log"
"fmt"
"github.com/bwmarrin/discordgo"
)
var (
msgCount uint64
startID string
outputDir string
discordToken string
channelID string
)
func init() {
// necessary
flag.StringVar(&outputDir, "o", "", "The output dir.")
flag.StringVar(&discordToken, "t", "", "The discord token.")
flag.StringVar(&channelID, "i", "", "The discord channel id.")
// optional
flag.StringVar(&startID, "s", "", "The message start id.")
flag.Uint64Var(&msgCount, "c", 0, "The initial value for message count.")
flag.Parse()
// perform additional checks after parsing the flags
switch {
default:
outputDir = filepath.Clean(outputDir)
case outputDir == "":
panic("No output dir specified.")
case discordToken == "":
panic("No discord token specified.")
case channelID == "":
panic("No discord channel id specified.")
}
}
func main() {
// open discord bot api
dg, err := setupDiscord()
if err != nil {
panic(err)
}
defer dg.Close()
// download first batch of messages
msgs, err := getMessages(dg, startID)
if err != nil {
panic(err)
}
err = saveMessages(msgCount, msgs)
if err != nil {
panic(err)
}
// download the rest
sigs := make(chan os.Signal, 8)
signal.Notify(sigs, os.Kill, os.Interrupt)
for {
select {
case <-sigs:
return
default:
msgs, err = getMessages(dg, msgs[0].ID)
if err != nil {
panic(err)
}
if len(msgs) == 0 {
return
}
msgCount += uint64(len(msgs))
go func(msgCount uint64, msgs []*discordgo.Message) {
err := saveMessages(msgCount, msgs)
if err != nil {
panic(err)
}
}(msgCount, msgs)
}
}
}
func saveMessages(count uint64, msgs []*discordgo.Message) error {
// filename
path := fmt.Sprintf(`%s%c%024d.gob.gz`, outputDir, filepath.Separator, count)
log.Printf("saving %s\n", path)
// open file
f, err := os.Create(path)
if err != nil {
return err
}
defer f.Close()
// compressor
gz := gzip.NewWriter(f)
defer gz.Close()
return gob.NewEncoder(gz).Encode(msgs)
}
func getMessages(dg *discordgo.Session, before string) ([]*discordgo.Message, error) {
msgs, err := dg.ChannelMessages(channelID, -1, before, "", "")
if err != nil {
return nil, err
}
sort.Slice(msgs, func(i, j int) bool {
ti, _ := time.Parse(time.RFC3339Nano, string(msgs[i].Timestamp))
tj, _ := time.Parse(time.RFC3339Nano, string(msgs[j].Timestamp))
return ti.Before(tj)
})
return msgs, nil
}
func setupDiscord() (*discordgo.Session, error) {
dg, err := discordgo.New(discordToken)
if err != nil {
return nil, err
}
err = dg.Open()
if err != nil {
return nil, err
}
return dg, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment