Purpose built bot for archiving the AtlasNX Discord server. https://github.com/AtlasNX/Discord-Archive
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
4.6 KiB

  1. /*
  2. * Archive Bot
  3. * Copyright (c) 2020 Nichole Mattera
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License
  7. * as published by the Free Software Foundation; either version 2
  8. * of the License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. */
  19. package main
  20. import(
  21. "encoding/json"
  22. "flag"
  23. "fmt"
  24. "io"
  25. "io/ioutil"
  26. "net/http"
  27. "os"
  28. "github.com/bwmarrin/discordgo"
  29. )
  30. type Attachment struct {
  31. Filename string `json:"filename"`
  32. OriginalFilename string `json:"original_filename"`
  33. }
  34. type Message struct {
  35. Attachments []Attachment `json:"attachments"`
  36. AuthorID string `json:"author_id"`
  37. Author string `json:"author"`
  38. Content string `json:"content"`
  39. Reactions []Reaction `json:"reactions"`
  40. Timestamp string `json:"timestamp"`
  41. }
  42. type Reaction struct {
  43. Name string `json:"name"`
  44. Count int `json:"count"`
  45. }
  46. func main() {
  47. var token string
  48. var channelID string
  49. var lastMessageID string
  50. flag.StringVar(&token, "t", "", "The bot token. (Required)")
  51. flag.StringVar(&channelID, "c", "", "The channel ID. (Required)")
  52. flag.StringVar(&lastMessageID, "m", "", "The message ID to start archiving from, not including said message. If not specified it will archive all messages in the channel.")
  53. flag.Parse()
  54. if token == "" || channelID == "" {
  55. fmt.Println("Usage:")
  56. flag.PrintDefaults()
  57. return
  58. }
  59. discord, err := discordgo.New("Bot " + token)
  60. if err != nil {
  61. fmt.Println("Error creating Discord session: ", err)
  62. return
  63. }
  64. err = discord.Open()
  65. if err != nil {
  66. fmt.Println("error opening connection,", err)
  67. return
  68. }
  69. if _, err := os.Stat("./pfps"); os.IsNotExist(err) {
  70. os.Mkdir("./pfps", 0700)
  71. }
  72. if _, err := os.Stat("./" + channelID); os.IsNotExist(err) {
  73. os.Mkdir("./" + channelID, 0700)
  74. }
  75. archivedMessages := []Message{}
  76. numberOfMessages := 100
  77. for numberOfMessages == 100 {
  78. messages, err := discord.ChannelMessages(channelID, 100, lastMessageID, "", "")
  79. if err != nil {
  80. fmt.Println("error getting messages,", err)
  81. return
  82. }
  83. for index, message := range messages {
  84. // Download PfPs
  85. if _, err := os.Stat("./pfps/" + message.Author.ID); os.IsNotExist(err) {
  86. err = DownloadFile("./pfps/" + message.Author.ID, message.Author.AvatarURL(""))
  87. if err != nil {
  88. fmt.Println("error downloading PfP,", err)
  89. }
  90. }
  91. // Build Attachments
  92. archivedAttachments := []Attachment{}
  93. for _, attachment := range message.Attachments {
  94. if _, err := os.Stat("./" + channelID + "/" + message.ID + "_" + attachment.Filename); os.IsNotExist(err) {
  95. err = DownloadFile("./" + channelID + "/" + message.ID + "_" + attachment.Filename, attachment.URL)
  96. if err != nil {
  97. fmt.Println("error downloading attachment,", err)
  98. }
  99. }
  100. archivedAttachment := Attachment {
  101. message.ID + "_" + attachment.Filename,
  102. attachment.Filename,
  103. }
  104. archivedAttachments = append([]Attachment{ archivedAttachment }, archivedAttachments...)
  105. }
  106. // Build Reactions
  107. archivedReactions := []Reaction{}
  108. for _, reaction := range message.Reactions {
  109. archivedReaction := Reaction {
  110. reaction.Emoji.Name,
  111. reaction.Count,
  112. }
  113. archivedReactions = append([]Reaction{ archivedReaction }, archivedReactions...)
  114. }
  115. archivedMessage := Message {
  116. archivedAttachments,
  117. message.Author.ID,
  118. message.Author.Username + "#" + message.Author.Discriminator,
  119. message.Content,
  120. archivedReactions,
  121. string(message.Timestamp),
  122. }
  123. archivedMessages = append([]Message{ archivedMessage }, archivedMessages...)
  124. if index == len(messages) - 1 {
  125. lastMessageID = message.ID
  126. }
  127. }
  128. numberOfMessages = len(messages)
  129. }
  130. res, err := json.Marshal(archivedMessages)
  131. if err != nil {
  132. fmt.Println("error encoding messages to json,", err)
  133. return
  134. }
  135. err = ioutil.WriteFile("./" + channelID + ".json", res, 0644)
  136. discord.Close()
  137. }
  138. func DownloadFile(filepath string, url string) error {
  139. // Get the data
  140. resp, err := http.Get(url)
  141. if err != nil {
  142. return err
  143. }
  144. defer resp.Body.Close()
  145. // Create the file
  146. out, err := os.Create(filepath)
  147. if err != nil {
  148. return err
  149. }
  150. defer out.Close()
  151. // Write the body to file
  152. _, err = io.Copy(out, resp.Body)
  153. return err
  154. }