Complete rewrite to support new API.

This commit is contained in:
Kevin Thompson
2024-11-10 18:10:04 -06:00
parent 856e1b1cbd
commit 60130e243c
3 changed files with 105 additions and 84 deletions

View File

@ -1,9 +1,13 @@
package config package config
var ( var BotToken = ""
BotToken = "REDACTED"
CFBDAPIKey = "ay2L+7JSttYQP9e10qxpAkluht7NHcyEnSqbBUsqWrwVjBcl02QH2XjOaVDnPRBy" var CustomTeamNames = map[string]string{
) "UGA": "Georgia",
"Booger Eaters": "Auburn",
"Rape Enablers": "LSU",
"Checkerboard Clowns": "Tennessee",
}
func LoadConfig() { func LoadConfig() {
} }

View File

@ -1,41 +1,41 @@
package bot package bot
import ( import (
"fmt" "discord-cfb-bot/config"
"strings" "discord-cfb-bot/internal/clients"
"github.com/bwmarrin/discordgo"
"discord-cfb-bot/internal/clients/cfb" // Adjust this import path as needed "fmt"
"github.com/bwmarrin/discordgo" "strings"
) )
// MessageCreate handles incoming messages and triggers the appropriate response var Bot *discordgo.Session
func MessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
// Ignore messages from the bot itself
if m.Author.ID == s.State.User.ID {
return
}
// Command for fetching college football scores func Start() error {
if strings.HasPrefix(m.Content, "!cfb") { var err error
// Extract any arguments (e.g., week number) if needed Bot, err = discordgo.New("Bot " + config.BotToken)
weekNumber := 10 // Replace this with dynamic parsing if necessary
games, err := cfb.FetchScoreboard(weekNumber)
if err != nil { if err != nil {
s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Error fetching games: %s", err)) return fmt.Errorf("error creating a Discord session: %w", err)
return
} }
if len(games) == 0 { fmt.Println("Discord session created successfully")
s.ChannelMessageSend(m.ChannelID, "No games found for this week.")
return
}
// Send formatted game summaries Bot.AddHandler(commandHandler)
for _, game := range games { err = Bot.Open()
gameSummary := cfb.FormatGameOutput(game) if err != nil {
s.ChannelMessageSend(m.ChannelID, gameSummary) 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 strings.HasPrefix(m.Content, "!cfb ") {
teamName := strings.TrimSpace(strings.TrimPrefix(m.Content, "!cfb "))
response := cfb.GetGameInfo(teamName)
s.ChannelMessageSend(m.ChannelID, response)
}
}

View File

@ -1,81 +1,98 @@
package cfb ipackage cfb
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"os" "strings"
"time"
"discord-cfb-bot/config"
) )
// Game represents the structure of a single game
type Game struct { type Game struct {
AwayTeam string `json:"away_team"` Game struct {
AwayScore string `json:"away_score"` GameID string `json:"gameID"`
HomeTeam string `json:"home_team"` StartDate string `json:"startDate"`
HomeScore string `json:"home_score"` StartTime string `json:"startTime"`
GameState string `json:"game_state"` GameState string `json:"gameState"`
CurrentPeriod string `json:"current_period"` CurrentPeriod string `json:"currentPeriod"`
StartTime string `json:"start_time"` ContestClock string `json:"contestClock"`
ContestClock string `json:"contest_clock"` Home Team `json:"home"`
StartTimeEpoch int64 `json:"start_time_epoch"` Away Team `json:"away"`
FinalMessage string `json:"finalMessage"`
} `json:"game"`
} }
// FetchScoreboard retrieves and parses the scoreboard data from the specified API URL type Team struct {
func FetchScoreboard(weekNumber int) ([]Game, error) { Score string `json:"score"`
apiKey := os.Getenv("CFBD_API_KEY") Names struct {
if apiKey == "" { Short string `json:"short"`
return nil, errors.New("missing API key") Full string `json:"full"`
} `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
}
} }
url := fmt.Sprintf("https://ncaa.ewnix.net/scoreboard/football/fbs/2024/%d/all-conf", weekNumber) apiURL := "https://ncaa.ewnix.net/scoreboard/football/fbs/2024/all-conf"
req, _ := http.NewRequest("GET", url, nil) resp, err := http.Get(apiURL)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey))
client := &http.Client{}
resp, err := client.Do(req)
if err != nil { if err != nil {
return nil, err return fmt.Sprintf("Failed to reach the scoreboard API: %v", err)
} }
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to fetch scoreboard, status code: %d", resp.StatusCode) return fmt.Sprintf("Failed to reach the scoreboard API. Status code: %d", resp.StatusCode)
} }
body, _ := ioutil.ReadAll(resp.Body) body, _ := ioutil.ReadAll(resp.Body)
var data struct {
Games []struct { var apiResponse struct {
Game Game `json:"game"` Games []Game `json:"games"`
} `json:"games"` }
if err := json.Unmarshal(body, &apiResponse); err != nil {
return "Error parsing the API response."
} }
if err := json.Unmarshal(body, &data); err != nil { var results []string
return nil, fmt.Errorf("error parsing scoreboard: %w", err)
}
games := make([]Game, len(data.Games)) for _, game := range apiResponse.Games {
for i, g := range data.Games { // Filter games by team name (either home or away)
// Adjust start time by subtracting 5 hours for upcoming games if strings.ToLower(game.Game.Home.Names.Short) == teamNameLower ||
if g.Game.GameState == "upcoming" { strings.ToLower(game.Game.Away.Names.Short) == teamNameLower {
epochTime := time.Unix(g.Game.StartTimeEpoch, 0).Add(-5 * time.Hour)
g.Game.StartTime = epochTime.Format("03:04PM ET") var gameInfo string
if game.Game.GameState == "in_progress" {
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" {
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",
game.Game.Away.Names.Short, game.Game.Away.Score,
game.Game.Home.Names.Short, game.Game.Home.Score)
}
results = append(results, gameInfo)
} }
games[i] = g.Game
} }
return games, nil if len(results) > 0 {
} return strings.Join(results, "\n")
// FormatGameOutput formats the game data into a string
func FormatGameOutput(game Game) string {
if game.GameState == "live" {
return fmt.Sprintf("%s: *%s* %s: *%s* Quarter: %s Time Remaining: %s",
game.AwayTeam, game.AwayScore, game.HomeTeam, game.HomeScore, game.CurrentPeriod, game.ContestClock)
} }
return fmt.Sprintf("%s: %s %s: %s Final",
game.AwayTeam, game.AwayScore, game.HomeTeam, game.HomeScore)
}
return "No game found for the specified team."
}