From 1e460a2c09879f25c7f8f73594dd31e8963d15db Mon Sep 17 00:00:00 2001 From: phlux Date: Sun, 10 Nov 2024 21:18:37 -0500 Subject: [PATCH] Holy shit this was hard --- internal/bot/bot.go | 90 ++++++++++++++++++++++++------------- internal/clients/cbb/cbb.go | 46 ++++++++++++------- internal/clients/cfb/cfb.go | 49 ++++++++++++-------- 3 files changed, 119 insertions(+), 66 deletions(-) diff --git a/internal/bot/bot.go b/internal/bot/bot.go index 4213cdf..f1c2d54 100644 --- a/internal/bot/bot.go +++ b/internal/bot/bot.go @@ -1,48 +1,76 @@ package bot import ( - "discord-cfb-bot/config" - cfbClient "discord-cfb-bot/internal/clients/cfb" - cbbClient "discord-cfb-bot/internal/clients/cbb" - "github.com/bwmarrin/discordgo" - "fmt" - "strings" + "discord-cfb-bot/config" + cfbClient "discord-cfb-bot/internal/clients/cfb" + cbbClient "discord-cfb-bot/internal/clients/cbb" + "github.com/bwmarrin/discordgo" + "fmt" + "strings" ) var Bot *discordgo.Session func Start() error { - var err error - Bot, err = discordgo.New("Bot " + config.BotToken) - if err != nil { - return fmt.Errorf("error creating a Discord session: %w", err) - } + var err error + Bot, err = discordgo.New("Bot " + config.BotToken) + if err != nil { + return fmt.Errorf("error creating a Discord session: %w", err) + } - fmt.Println("Discord session created successfully") + fmt.Println("Discord session created successfully") - Bot.AddHandler(commandHandler) - err = Bot.Open() - if err != nil { - return fmt.Errorf("Error opening connection: %w", err) - } - fmt.Println("Bot is now running.") - return nil + Bot.AddHandler(commandHandler) + err = Bot.Open() + if err != nil { + return fmt.Errorf("error opening connection: %w", err) + } + fmt.Println("Bot is now running.") + return nil } func commandHandler(s *discordgo.Session, m *discordgo.MessageCreate) { - if m.Author.Bot { - return + if m.Author.Bot { + return + } + + if strings.HasPrefix(m.Content, "!cfb ") { + teamName := strings.TrimSpace(strings.TrimPrefix(m.Content, "!cfb ")) + response := cfbClient.GetGameInfo(teamName) + s.ChannelMessageSend(m.ChannelID, response) + } + + if strings.HasPrefix(m.Content, "!cbb ") { + content := strings.TrimSpace(strings.TrimPrefix(m.Content, "!cbb ")) + parts := strings.SplitN(content, " ", 2) + + teamName := parts[0] + date := "" + if len(parts) > 1 { + if isDateFormat(parts[1]) { + date = parts[1] + } else { + teamName = content // Reset team name to include all parts if no valid date + } } - if strings.HasPrefix(m.Content, "!cfb ") { - teamName := strings.TrimSpace(strings.TrimPrefix(m.Content, "!cfb ")) - response := cfbClient.GetGameInfo(teamName) - s.ChannelMessageSend(m.ChannelID, response) + // Check if the team name is a custom name defined in config + if customTeam, exists := config.CustomTeamNames[strings.ToLower(teamName)]; exists { + response := cbbClient.GetGameInfo(customTeam, date) // Exact match for custom teams + s.ChannelMessageSend(m.ChannelID, response) + } else { + response := cbbClient.GetGameInfo(teamName, date) // General match for all teams + s.ChannelMessageSend(m.ChannelID, response) } - - if strings.HasPrefix(m.Content, "!cbb ") { - teamName := strings.TrimSpace(strings.TrimPrefix(m.Content, "!cbb ")) - response := cbbClient.GetGameInfo(teamName) - s.ChannelMessageSend(m.ChannelID, response) - } + } } + +// isDateFormat checks if a string is in the MM/DD format +func isDateFormat(dateStr string) bool { + parts := strings.Split(dateStr, "/") + if len(parts) != 2 { + return false + } + return len(parts[0]) <= 2 && len(parts[1]) <= 2 // Simple check for MM/DD format +} + diff --git a/internal/clients/cbb/cbb.go b/internal/clients/cbb/cbb.go index ef8678d..25682f4 100644 --- a/internal/clients/cbb/cbb.go +++ b/internal/clients/cbb/cbb.go @@ -6,8 +6,8 @@ import ( "io/ioutil" "net/http" "strings" - - "discord-cfb-bot/config" + "time" + "unicode" ) type Game struct { @@ -32,19 +32,27 @@ type Team struct { } `json:"names"` } -func GetGameInfo(teamName string) string { - // Make the teamName input lowercase - teamNameLower := strings.ToLower(teamName) - - // Check if the lowercase teamName matches a custom abbreviation - for key, value := range config.CustomTeamNames { - if strings.ToLower(key) == teamNameLower { - teamNameLower = strings.ToLower(value) - break +func GetGameInfo(teamName, date string) string { + // If no date is provided, use today's date + if date == "" { + date = time.Now().Format("2006/01/02") // Format as YYYY/MM/DD + } else { + // Check if the last 5 characters are in MM/DD format for date input + if len(date) == 5 && unicode.IsDigit(rune(date[0])) && unicode.IsDigit(rune(date[1])) && date[2] == '/' && + unicode.IsDigit(rune(date[3])) && unicode.IsDigit(rune(date[4])) { + date = fmt.Sprintf("2024/%s", strings.ReplaceAll(date, "/", "/")) // Add the year and reformat + } else { + return "Invalid date format. Please use MM/DD." } } - apiURL := "https://ncaa.ewnix.net/scoreboard/basketball-men/d1" + apiURL := fmt.Sprintf("https://ncaa.ewnix.net/scoreboard/basketball-men/d1/%s", date) + return fetchAndParseGames(apiURL, teamName) +} + +func fetchAndParseGames(apiURL, teamName string) string { + teamNameLower := strings.ToLower(teamName) + resp, err := http.Get(apiURL) if err != nil { return fmt.Sprintf("Failed to reach the scoreboard API: %v", err) @@ -67,17 +75,20 @@ func GetGameInfo(teamName string) string { var results []string for _, game := range apiResponse.Games { - // Filter games by team name (either home or away) if strings.ToLower(game.Game.Home.Names.Short) == teamNameLower || strings.ToLower(game.Game.Away.Names.Short) == teamNameLower { var gameInfo string - if game.Game.GameState == "in_progress" { - gameInfo = fmt.Sprintf("%s: **%s** %s: **%s** | Half: %s | Time Remaining: %s", + if game.Game.GameState == "live" { + currentPeriod := game.Game.CurrentPeriod + if currentPeriod == "" { + currentPeriod = "HALFTIME" + } + gameInfo = fmt.Sprintf("Live: %s: **%s** %s: **%s** | Half: %s | Time Remaining: %s", game.Game.Away.Names.Short, game.Game.Away.Score, game.Game.Home.Names.Short, game.Game.Home.Score, - game.Game.CurrentPeriod, game.Game.ContestClock) - } else if game.Game.GameState == "scheduled" { + currentPeriod, game.Game.ContestClock) + } else if game.Game.GameState == "pre" { gameInfo = fmt.Sprintf("Upcoming: %s @ %s on %s at %s ET", game.Game.Away.Names.Short, game.Game.Home.Names.Short, game.Game.StartDate, game.Game.StartTime) } else if game.Game.GameState == "final" { @@ -96,3 +107,4 @@ func GetGameInfo(teamName string) string { return "No game found for the specified team." } + diff --git a/internal/clients/cfb/cfb.go b/internal/clients/cfb/cfb.go index da1e10c..da877a3 100644 --- a/internal/clients/cfb/cfb.go +++ b/internal/clients/cfb/cfb.go @@ -4,10 +4,10 @@ import ( "encoding/json" "fmt" "io/ioutil" + "log" "net/http" "strings" - - "discord-cfb-bot/config" + "unicode" ) type Game struct { @@ -33,18 +33,24 @@ type Team struct { } func GetGameInfo(teamName string) string { - // Make the teamName input lowercase - teamNameLower := strings.ToLower(teamName) + teamName = strings.TrimSpace(teamName) + week := "" - // Check if the lowercase teamName matches a custom abbreviation - for key, value := range config.CustomTeamNames { - if strings.ToLower(key) == teamNameLower { - teamNameLower = strings.ToLower(value) - break - } + // Check if the last two characters of the input are integers for the week + if len(teamName) >= 2 && unicode.IsDigit(rune(teamName[len(teamName)-1])) && unicode.IsDigit(rune(teamName[len(teamName)-2])) { + week = teamName[len(teamName)-2:] + teamName = strings.TrimSpace(teamName[:len(teamName)-2]) + log.Printf("Week detected: %s", week) } - apiURL := "https://ncaa.ewnix.net/scoreboard/football/fbs/2024/all-conf" + // Build the API URL based on whether a week is provided + apiURL := "https://ncaa.ewnix.net/scoreboard/football/fbs" + if week != "" { + apiURL = fmt.Sprintf("https://ncaa.ewnix.net/scoreboard/football/fbs/2024/%s/all-conf", week) + } + + log.Printf("Fetching data from API: %s", apiURL) + resp, err := http.Get(apiURL) if err != nil { return fmt.Sprintf("Failed to reach the scoreboard API: %v", err) @@ -65,23 +71,29 @@ func GetGameInfo(teamName string) string { } var results []string + teamNameLower := strings.ToLower(teamName) for _, game := range apiResponse.Games { - // Filter games by team name (either home or away) - if strings.ToLower(game.Game.Home.Names.Short) == teamNameLower || - strings.ToLower(game.Game.Away.Names.Short) == teamNameLower { + homeTeamLowerShort := strings.ToLower(game.Game.Home.Names.Short) + awayTeamLowerShort := strings.ToLower(game.Game.Away.Names.Short) + // Check if the team matches the short name only + if homeTeamLowerShort == teamNameLower || awayTeamLowerShort == teamNameLower { var gameInfo string - if game.Game.GameState == "in_progress" { + if game.Game.GameState == "live" { + period := game.Game.CurrentPeriod + if period == "" { + period = "HALFTIME" + } gameInfo = fmt.Sprintf("%s: **%s** %s: **%s** | Quarter: %s | Time Remaining: %s", game.Game.Away.Names.Short, game.Game.Away.Score, game.Game.Home.Names.Short, game.Game.Home.Score, - game.Game.CurrentPeriod, game.Game.ContestClock) - } else if game.Game.GameState == "scheduled" { + period, game.Game.ContestClock) + } else if game.Game.GameState == "pre" { gameInfo = fmt.Sprintf("Upcoming: %s @ %s on %s at %s ET", game.Game.Away.Names.Short, game.Game.Home.Names.Short, game.Game.StartDate, game.Game.StartTime) } else if game.Game.GameState == "final" { - gameInfo = fmt.Sprintf("Final: %s: %s %s: %s", + gameInfo = fmt.Sprintf("Final: %s: **%s** %s: **%s**", game.Game.Away.Names.Short, game.Game.Away.Score, game.Game.Home.Names.Short, game.Game.Home.Score) } @@ -96,3 +108,4 @@ func GetGameInfo(teamName string) string { return "No game found for the specified team." } +