A modular Twitch bot made in Go
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.

184 lines
3.5 KiB

2 years ago
2 years ago
  1. package twitchbot
  2. import "log"
  3. type EventHandler struct {
  4. messageHandlers []func(*Bot, *Message)
  5. }
  6. type Bot struct {
  7. client *Client
  8. host string
  9. onLogin func(*Bot)
  10. events EventHandler
  11. channels []string
  12. }
  13. type User struct {
  14. ID string
  15. Name string
  16. }
  17. type Message struct {
  18. ID string
  19. Channel string
  20. User *User
  21. Message string
  22. Bot *Bot
  23. }
  24. func ParseMessage(command *Command, bot *Bot) *Message {
  25. return &Message{
  26. ID: command.Tags["id"],
  27. Channel: command.Args[0][1:],
  28. User: &User{ID: command.Tags["user-id"], Name: command.Tags["display-name"]},
  29. Message: command.Suffix,
  30. Bot: bot,
  31. }
  32. }
  33. func NewBot(token string, nick string, channels []string) *Bot {
  34. client := Client{Token: token, Nick: nick}
  35. return &Bot{client: &client, host: "irc.chat.twitch.tv:6667", events: EventHandler{}, channels: channels}
  36. }
  37. func (message *Message) Reply(msg string) error {
  38. err := message.Bot.SendMessage(&Message{Message: msg, Channel: message.Channel})
  39. if err != nil {
  40. return err
  41. }
  42. return nil
  43. }
  44. func (message *Message) Delete() error {
  45. err := message.Bot.DeleteMessage(&Message{ID: message.ID, Channel: message.Channel})
  46. if err != nil {
  47. return err
  48. }
  49. return nil
  50. }
  51. func (message *Message) Ban() error {
  52. err := message.Bot.BanUser(message.Channel, message.User.Name)
  53. if err != nil {
  54. return err
  55. }
  56. return nil
  57. }
  58. func (event *EventHandler) configure(bot *Bot) {
  59. bot.client.AddHandler("PRIVMSG", func(command *Command) bool {
  60. message := ParseMessage(command, bot)
  61. for _, handler := range event.messageHandlers {
  62. go handler(bot, message)
  63. }
  64. return true
  65. })
  66. }
  67. func (bot *Bot) OnLogin(f func(*Bot)) {
  68. bot.onLogin = f
  69. }
  70. func (bot *Bot) SendMessage(message *Message) error {
  71. err := bot.client.Send(&Command{Command: "PRIVMSG", Args: []string{"#" + message.Channel}, Suffix: message.Message})
  72. if err != nil {
  73. return err
  74. }
  75. return nil
  76. }
  77. func (bot *Bot) DeleteMessage(message *Message) error {
  78. err := bot.SendMessage(&Message{Channel: message.Channel, Message: "/delete " + message.ID})
  79. if err != nil {
  80. return err
  81. }
  82. return nil
  83. }
  84. func (bot *Bot) Join(channel string) error {
  85. err := bot.client.Join("#" + channel)
  86. if err != nil {
  87. return err
  88. }
  89. return nil
  90. }
  91. func (bot *Bot) BanUser(channel string, user string) error {
  92. err := bot.SendMessage(&Message{Channel: channel, Message: "/ban " + user})
  93. if err != nil {
  94. return err
  95. }
  96. return nil
  97. }
  98. func (bot *Bot) OnMessage(f func(*Bot, *Message)) {
  99. bot.events.messageHandlers = append(bot.events.messageHandlers, f)
  100. }
  101. func (bot *Bot) GetClient() *Client {
  102. return bot.client
  103. }
  104. func (bot *Bot) Run() {
  105. for {
  106. err := bot.Start()
  107. if err != nil {
  108. log.Printf("Bot error: %s\n", err)
  109. }
  110. }
  111. }
  112. func (bot *Bot) Start() error {
  113. err := bot.client.Connect(bot.host)
  114. if err != nil {
  115. return err
  116. }
  117. defer bot.client.Close()
  118. err = bot.client.Connect(bot.host)
  119. if err != nil {
  120. return err
  121. }
  122. err = bot.client.Auth()
  123. if err != nil {
  124. return err
  125. }
  126. bot.events.configure(bot)
  127. bot.client.AddHandler("PING", func(command *Command) bool {
  128. err := bot.client.Send(&Command{Command: "PONG", Suffix: "tmi.twitch.tv"})
  129. if err != nil {
  130. return false
  131. }
  132. return true
  133. })
  134. bot.client.AddHandler("376", func(command *Command) bool {
  135. err = bot.GetClient().CapReq("twitch.tv/tags twitch.tv/commands")
  136. if err != nil {
  137. return false
  138. }
  139. for _, channel := range bot.channels {
  140. err = bot.Join(channel)
  141. if err != nil {
  142. return false
  143. }
  144. }
  145. if bot.onLogin != nil {
  146. bot.onLogin(bot)
  147. }
  148. return true
  149. })
  150. err = bot.client.Handle()
  151. if err != nil {
  152. return err
  153. }
  154. return nil
  155. }