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.

179 lines
3.5 KiB

2 years ago
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. defer bot.client.Close()
  114. err := bot.client.Connect(bot.host)
  115. if err != nil {
  116. return err
  117. }
  118. err = bot.client.Auth()
  119. if err != nil {
  120. return err
  121. }
  122. bot.events.configure(bot)
  123. bot.client.AddHandler("PING", func(command *Command) bool {
  124. err := bot.client.Send(&Command{Command: "PONG", Suffix: "tmi.twitch.tv"})
  125. if err != nil {
  126. return false
  127. }
  128. return true
  129. })
  130. bot.client.AddHandler("376", func(command *Command) bool {
  131. err = bot.GetClient().CapReq("twitch.tv/tags twitch.tv/commands")
  132. if err != nil {
  133. return false
  134. }
  135. for _, channel := range bot.channels {
  136. err = bot.Join(channel)
  137. if err != nil {
  138. return false
  139. }
  140. }
  141. if bot.onLogin != nil {
  142. bot.onLogin(bot)
  143. }
  144. return true
  145. })
  146. err = bot.client.Handle()
  147. if err != nil {
  148. return err
  149. }
  150. return nil
  151. }