128 lines
3.2 KiB
Go
128 lines
3.2 KiB
Go
package clients
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"log"
|
|
"net"
|
|
"net/textproto"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type TwitchBot struct {
|
|
conn net.Conn
|
|
reader *textproto.Reader
|
|
username string
|
|
oauth string
|
|
clientID string
|
|
channel string
|
|
}
|
|
|
|
func NewTwitchBot(username, oauth, clientID, channel string) *TwitchBot {
|
|
return &TwitchBot{
|
|
username: username,
|
|
oauth: oauth,
|
|
clientID: clientID,
|
|
channel: channel,
|
|
}
|
|
}
|
|
|
|
func (bot *TwitchBot) Connect() error {
|
|
var err error
|
|
bot.conn, err = net.Dial("tcp", "irc.chat.twitch.tv:6667")
|
|
if err != nil {
|
|
return fmt.Errorf("failed to connect to Twitch IRC: %v", err)
|
|
}
|
|
|
|
bot.reader = textproto.NewReader(bufio.NewReader(bot.conn))
|
|
|
|
// Authenticate with IRC (Client ID not needed for IRC connection)
|
|
fmt.Fprintf(bot.conn, "PASS %s\r\n", bot.oauth)
|
|
fmt.Fprintf(bot.conn, "NICK %s\r\n", bot.username)
|
|
fmt.Fprintf(bot.conn, "CAP REQ :twitch.tv/membership\r\n")
|
|
fmt.Fprintf(bot.conn, "CAP REQ :twitch.tv/tags\r\n")
|
|
fmt.Fprintf(bot.conn, "CAP REQ :twitch.tv/commands\r\n")
|
|
|
|
// Join channel
|
|
fmt.Fprintf(bot.conn, "JOIN #%s\r\n", bot.channel)
|
|
|
|
log.Printf("Connected to Twitch IRC and joined #%s", bot.channel)
|
|
log.Printf("Client ID ready for Helix API calls: %s", bot.clientID[:8]+"...")
|
|
return nil
|
|
}
|
|
|
|
func (bot *TwitchBot) SendMessage(message string) error {
|
|
_, err := fmt.Fprintf(bot.conn, "PRIVMSG #%s :%s\r\n", bot.channel, message)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to send message: %v", err)
|
|
}
|
|
log.Printf("Sent message: %s", message)
|
|
return nil
|
|
}
|
|
|
|
// GetClientID returns the client ID for potential Helix API usage
|
|
func (bot *TwitchBot) GetClientID() string {
|
|
return bot.clientID
|
|
}
|
|
|
|
// GetOAuthToken returns the OAuth token (without oauth: prefix) for Helix API usage
|
|
func (bot *TwitchBot) GetOAuthToken() string {
|
|
// Remove oauth: prefix for API calls
|
|
return strings.TrimPrefix(bot.oauth, "oauth:")
|
|
}
|
|
|
|
func (bot *TwitchBot) HandleMessages() {
|
|
for {
|
|
line, err := bot.reader.ReadLine()
|
|
if err != nil {
|
|
log.Printf("Error reading from connection: %v", err)
|
|
break
|
|
}
|
|
|
|
// Handle PING messages to keep connection alive
|
|
if strings.HasPrefix(line, "PING") {
|
|
pong := strings.Replace(line, "PING", "PONG", 1)
|
|
fmt.Fprintf(bot.conn, "%s\r\n", pong)
|
|
continue
|
|
}
|
|
|
|
// Log incoming messages (optional - remove if you don't want to see chat)
|
|
if strings.Contains(line, "PRIVMSG") {
|
|
// Parse username from message for cleaner logging
|
|
if idx := strings.Index(line, "!"); idx != -1 {
|
|
username := line[1:idx]
|
|
if msgIdx := strings.Index(line, " :"); msgIdx != -1 {
|
|
message := line[msgIdx+2:]
|
|
log.Printf("[%s]: %s", username, message)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (bot *TwitchBot) StartFishTimer() {
|
|
// Send initial !fish message after a short delay
|
|
time.Sleep(2 * time.Second)
|
|
if err := bot.SendMessage("!fish"); err != nil {
|
|
log.Printf("Error sending initial !fish: %v", err)
|
|
}
|
|
|
|
// Set up timer for every 5 minutes
|
|
ticker := time.NewTicker(5 * time.Minute)
|
|
defer ticker.Stop()
|
|
|
|
for range ticker.C {
|
|
if err := bot.SendMessage("!fish"); err != nil {
|
|
log.Printf("Error sending !fish: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (bot *TwitchBot) Close() {
|
|
if bot.conn != nil {
|
|
log.Println("Closing connection to Twitch IRC")
|
|
bot.conn.Close()
|
|
}
|
|
}
|